merge heads

This commit is contained in:
Jimmy Shih
2012-04-10 10:31:02 -07:00
commit 2fbdb9bfef
582 changed files with 62438 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="src" path=".apt_generated">
<attributes>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/MyTracks"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>
+7
View File
@@ -0,0 +1,7 @@
<factorypath>
<factorypathentry kind="WKSPJAR" id="/MyTracksTest/libs/AndroidMockGenerator.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="ANDROID_SDK/platforms/android-15/android.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="ANDROID_SDK/add-ons/addon-google_apis-google_inc_-15/libs/maps.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="WKSPJAR" id="/MyTracksLib/bin/mytrackslib.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="MYTRACKS_BIN/classes" enabled="true" runInBatchMode="false"/>
</factorypath>
+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>MyTracksTest</name>
<comment></comment>
<projects>
<project>MyTracks</project>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
@@ -0,0 +1,7 @@
#Tue Oct 25 14:08:44 PDT 2011
eclipse.preferences.version=1
org.eclipse.jdt.apt.aptEnabled=true
org.eclipse.jdt.apt.genSrcDir=.apt_generated
org.eclipse.jdt.apt.processorOptions/bin_dir=%PROJECT.DIR%/bin/classes
org.eclipse.jdt.apt.processorOptions/logfile=%PROJECT.DIR%/AnnotationProcessor.log
org.eclipse.jdt.apt.reconcileEnabled=false
@@ -0,0 +1,358 @@
#Fri Oct 21 20:06:28 BRST 2011
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
org.eclipse.jdt.core.compiler.problem.deadCode=warning
org.eclipse.jdt.core.compiler.problem.deprecation=warning
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
org.eclipse.jdt.core.compiler.problem.nullReference=warning
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=disabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=disabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.processAnnotations=enabled
org.eclipse.jdt.core.compiler.source=1.6
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=48
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=48
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=48
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=true
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
org.eclipse.jdt.core.formatter.comment.line_length=80
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=2
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=true
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=false
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
org.eclipse.jdt.core.formatter.indentation.size=4
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.lineSplit=100
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
org.eclipse.jdt.core.formatter.tabulation.char=space
org.eclipse.jdt.core.formatter.tabulation.size=2
org.eclipse.jdt.core.formatter.use_on_off_tags=false
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
@@ -0,0 +1,61 @@
#Thu Jul 21 03:06:24 BRT 2011
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
formatter_profile=_MyTracks
formatter_settings_version=12
org.eclipse.jdt.ui.ignorelowercasenames=true
org.eclipse.jdt.ui.importorder=com;android;java;javax;org;
org.eclipse.jdt.ui.ondemandthreshold=99
org.eclipse.jdt.ui.staticondemandthreshold=99
sp_cleanup.add_default_serial_version_id=true
sp_cleanup.add_generated_serial_version_id=false
sp_cleanup.add_missing_annotations=true
sp_cleanup.add_missing_deprecated_annotations=true
sp_cleanup.add_missing_methods=false
sp_cleanup.add_missing_nls_tags=false
sp_cleanup.add_missing_override_annotations=true
sp_cleanup.add_missing_override_annotations_interface_methods=true
sp_cleanup.add_serial_version_id=false
sp_cleanup.always_use_blocks=true
sp_cleanup.always_use_parentheses_in_expressions=false
sp_cleanup.always_use_this_for_non_static_field_access=false
sp_cleanup.always_use_this_for_non_static_method_access=false
sp_cleanup.convert_to_enhanced_for_loop=false
sp_cleanup.correct_indentation=false
sp_cleanup.format_source_code=false
sp_cleanup.format_source_code_changes_only=false
sp_cleanup.make_local_variable_final=false
sp_cleanup.make_parameters_final=false
sp_cleanup.make_private_fields_final=true
sp_cleanup.make_type_abstract_if_missing_method=false
sp_cleanup.make_variable_declarations_final=true
sp_cleanup.never_use_blocks=false
sp_cleanup.never_use_parentheses_in_expressions=true
sp_cleanup.on_save_use_additional_actions=false
sp_cleanup.organize_imports=true
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
sp_cleanup.remove_private_constructors=true
sp_cleanup.remove_trailing_whitespaces=false
sp_cleanup.remove_trailing_whitespaces_all=true
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
sp_cleanup.remove_unnecessary_casts=true
sp_cleanup.remove_unnecessary_nls_tags=false
sp_cleanup.remove_unused_imports=false
sp_cleanup.remove_unused_local_variables=false
sp_cleanup.remove_unused_private_fields=true
sp_cleanup.remove_unused_private_members=false
sp_cleanup.remove_unused_private_methods=true
sp_cleanup.remove_unused_private_types=true
sp_cleanup.sort_members=false
sp_cleanup.sort_members_all=false
sp_cleanup.use_blocks=false
sp_cleanup.use_blocks_only_for_return_and_throw=false
sp_cleanup.use_parentheses_in_expressions=false
sp_cleanup.use_this_for_non_static_field_access=false
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
sp_cleanup.use_this_for_non_static_method_access=false
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+36
View File
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2012 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.maps.mytracks.test"
android:versionCode="1"
android:versionName="1.0" >
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.google.android.maps.mytracks" />
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="15" />
<application
android:icon="@android:drawable/sym_def_app_icon"
android:label="My Tracks Tests" >
<uses-library android:name="android.test.runner" />
</application>
</manifest>
+27
View File
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="com.android.ide.eclipse.adt.junit.launchConfigurationType">
<stringAttribute key="com.android.ide.eclipse.adt.commandline" value=""/>
<intAttribute key="com.android.ide.eclipse.adt.delay" value="0"/>
<stringAttribute key="com.android.ide.eclipse.adt.instrumentation" value="android.test.InstrumentationTestRunner"/>
<booleanAttribute key="com.android.ide.eclipse.adt.nobootanim" value="true"/>
<intAttribute key="com.android.ide.eclipse.adt.speed" value="0"/>
<booleanAttribute key="com.android.ide.eclipse.adt.target" value="true"/>
<booleanAttribute key="com.android.ide.eclipse.adt.wipedata" value="false"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/MyTracksTests"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=MyTracksTests"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="MyTracksTests"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value=""/>
</launchConfiguration>
Binary file not shown.
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<lint>
</lint>
+13
View File
@@ -0,0 +1,13 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
target=Google Inc.:Google APIs:15
@@ -0,0 +1,53 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.maps.mytracks.R;
import android.test.AndroidTestCase;
/**
* Tests for the AntPreference.
*
* @author Youtao Liu
*/
public class AntPreferenceTest extends AndroidTestCase {
public void testNotPaired() {
AntPreference antPreference = new AntPreference(getContext()) {
@Override
protected int getPersistedInt(int defaultReturnValue) {
return 0;
}
};
assertEquals(getContext().getString(R.string.settings_sensor_ant_not_paired),
antPreference.getSummary());
}
public void testPaired() {
int persistInt = 1;
AntPreference antPreference = new AntPreference(getContext()) {
@Override
protected int getPersistedInt(int defaultReturnValue) {
return 1;
}
};
assertEquals(
getContext().getString(R.string.settings_sensor_ant_paired, persistInt),
antPreference.getSummary());
}
}
@@ -0,0 +1,91 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.services.TrackRecordingService;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.test.AndroidTestCase;
import java.util.List;
/**
* Tests for the BootReceiver.
*
* @author Youtao Liu
*/
public class BootReceiverTest extends AndroidTestCase {
private static final String SERVICE_NAME = "com.google.android.apps.mytracks.services.TrackRecordingService";
/**
* Tests the behavior when receive notification which is the phone boot.
*/
public void testOnReceive_startService() {
// Make sure no TrackRecordingService
Intent stopIntent = new Intent(getContext(), TrackRecordingService.class);
getContext().stopService(stopIntent);
assertFalse(isServiceExisted(getContext(), SERVICE_NAME));
BootReceiver bootReceiver = new BootReceiver();
Intent intent = new Intent();
intent.setAction(Intent.ACTION_BOOT_COMPLETED);
bootReceiver.onReceive(getContext(), intent);
// Check if the service is started
assertTrue(isServiceExisted(getContext(), SERVICE_NAME));
}
/**
* Tests the behavior when receive notification which is not the phone boot.
*/
public void testOnReceive_noStartService() {
// Make sure no TrackRecordingService
Intent stopIntent = new Intent(getContext(), TrackRecordingService.class);
getContext().stopService(stopIntent);
assertFalse(isServiceExisted(getContext(), SERVICE_NAME));
BootReceiver bootReceiver = new BootReceiver();
Intent intent = new Intent();
intent.setAction(Intent.ACTION_BUG_REPORT);
bootReceiver.onReceive(getContext(), intent);
// Check if the service is not started
assertFalse(isServiceExisted(getContext(), SERVICE_NAME));
}
/**
* Checks if a service is started in a context.
*
* @param context the context for checking a service
* @param serviceName the service name to find if existed
*/
private boolean isServiceExisted(Context context, String serviceName) {
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> serviceList = activityManager
.getRunningServices(Integer.MAX_VALUE);
for (int i = 0; i < serviceList.size(); i++) {
RunningServiceInfo serviceInfo = serviceList.get(i);
ComponentName componentName = serviceInfo.service;
if (componentName.getClassName().equals(serviceName)) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,327 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.util.UnitConversions;
import android.location.Location;
import android.test.AndroidTestCase;
/**
* Tests {@link ChartFragment}.
*
* @author Youtao Liu
*/
public class ChartFragmentTest extends AndroidTestCase {
private ChartFragment chartFragment;
private final double HOURS_PER_UNIT = 60.0;
@Override
protected void setUp() throws Exception {
chartFragment = new ChartFragment();
chartFragment.setChartView(new ChartView(getContext()));
}
/**
* Tests the logic to get the incorrect values of sensor in
* {@link ChartFragment#fillDataPoint(Location, double[])}
*/
public void testFillDataPoint_sensorIncorrect() {
MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation();
// No input.
double[] point = fillDataPointTestHelper(myTracksLocation);
assertEquals(Double.NaN, point[3]);
assertEquals(Double.NaN, point[4]);
assertEquals(Double.NaN, point[5]);
// Input incorrect state.
// Creates SensorData.
Sensor.SensorData.Builder powerData = Sensor.SensorData.newBuilder()
.setValue(20).setState(Sensor.SensorState.NONE);
Sensor.SensorData.Builder cadenceData = Sensor.SensorData.newBuilder()
.setValue(20).setState(Sensor.SensorState.NONE);
Sensor.SensorData.Builder heartRateData = Sensor.SensorData.newBuilder()
.setValue(20).setState(Sensor.SensorState.NONE);
// Creates SensorDataSet.
SensorDataSet sensorDataSet = myTracksLocation.getSensorDataSet();
sensorDataSet = sensorDataSet.toBuilder()
.setPower(powerData)
.setCadence(cadenceData)
.setHeartRate(heartRateData)
.build();
myTracksLocation.setSensorData(sensorDataSet);
// Test.
point = fillDataPointTestHelper(myTracksLocation);
assertEquals(Double.NaN, point[3]);
assertEquals(Double.NaN, point[4]);
assertEquals(Double.NaN, point[5]);
}
/**
* Tests the logic to get the correct values of sensor in
* {@link ChartFragment#fillDataPoint(Location, double[])}.
*/
public void testFillDataPoint_sensorCorrect() {
MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation();
// No input.
double[] point = fillDataPointTestHelper(myTracksLocation);
assertEquals(Double.NaN, point[3]);
assertEquals(Double.NaN, point[4]);
assertEquals(Double.NaN, point[5]);
// Creates SensorData.
Sensor.SensorData.Builder powerData = Sensor.SensorData.newBuilder()
.setValue(20).setState(Sensor.SensorState.SENDING);
Sensor.SensorData.Builder cadenceData = Sensor.SensorData.newBuilder()
.setValue(20).setState(Sensor.SensorState.SENDING);
Sensor.SensorData.Builder heartRateData = Sensor.SensorData.newBuilder()
.setValue(20).setState(Sensor.SensorState.SENDING);
// Creates SensorDataSet.
SensorDataSet sensorDataSet = myTracksLocation.getSensorDataSet();
sensorDataSet = sensorDataSet.toBuilder()
.setPower(powerData)
.setCadence(cadenceData)
.setHeartRate(heartRateData)
.build();
myTracksLocation.setSensorData(sensorDataSet);
// Test.
point = fillDataPointTestHelper(myTracksLocation);
assertEquals(20.0, point[3]);
assertEquals(20.0, point[4]);
assertEquals(20.0, point[5]);
}
/**
* Tests the logic to get the value of metric Distance in
* {@link ChartFragment#fillDataPoint(Location, double[])}.
*/
public void testFillDataPoint_distanceMetric() {
// By distance.
chartFragment.getChartView().setMode(ChartView.Mode.BY_DISTANCE);
// Resets last location and writes first location.
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
double[] point = fillDataPointTestHelper(myTracksLocation1);
assertEquals(0.0, point[0]);
// The second is a same location, just different time.
MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation();
point = fillDataPointTestHelper(myTracksLocation2);
assertEquals(0.0, point[0]);
// The third location is a new location, and use metric.
MyTracksLocation myTracksLocation3 = TrackStubUtils.createMyTracksLocation();
myTracksLocation3.setLatitude(23);
point = fillDataPointTestHelper(myTracksLocation3);
// Computes the distance between Latitude 22 and 23.
float[] results = new float[4];
Location.distanceBetween(myTracksLocation2.getLatitude(), myTracksLocation2.getLongitude(),
myTracksLocation3.getLatitude(), myTracksLocation3.getLongitude(), results);
double distance1 = results[0] * UnitConversions.M_TO_KM;
assertEquals(distance1, point[0]);
// The fourth location is a new location, and use metric.
MyTracksLocation myTracksLocation4 = TrackStubUtils.createMyTracksLocation();
myTracksLocation4.setLatitude(24);
point = fillDataPointTestHelper(myTracksLocation4);
// Computes the distance between Latitude 23 and 24.
Location.distanceBetween(myTracksLocation3.getLatitude(), myTracksLocation3.getLongitude(),
myTracksLocation4.getLatitude(), myTracksLocation4.getLongitude(), results);
double distance2 = results[0] * UnitConversions.M_TO_KM;
assertEquals((distance1 + distance2), point[0]);
}
/**
* Tests the logic to get the value of imperial Distance in
* {@link ChartFragment#fillDataPoint(Location, double[])}.
*/
public void testFillDataPoint_distanceImperial() {
// Setups to use imperial.
chartFragment.setMetricUnits(false);
// The first is a same location, just different time.
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
double[] point = fillDataPointTestHelper(myTracksLocation1);
assertEquals(0.0, point[0]);
// The second location is a new location, and use imperial.
MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation();
myTracksLocation2.setLatitude(23);
point = fillDataPointTestHelper(myTracksLocation2);
/*
* Computes the distance between Latitude 22 and 23. And for we set using
* imperial, the distance should be multiplied by UnitConversions.KM_TO_MI.
*/
float[] results = new float[4];
Location.distanceBetween(myTracksLocation1.getLatitude(), myTracksLocation1.getLongitude(),
myTracksLocation2.getLatitude(), myTracksLocation2.getLongitude(), results);
double distance1 = results[0] * UnitConversions.M_TO_KM * UnitConversions.KM_TO_MI;
assertEquals(distance1, point[0]);
// The third location is a new location, and use imperial.
MyTracksLocation myTracksLocation3 = TrackStubUtils.createMyTracksLocation();
myTracksLocation3.setLatitude(24);
point = fillDataPointTestHelper(myTracksLocation3);
/*
* Computes the distance between Latitude 23 and 24. And for we set using
* imperial, the distance should be multiplied by UnitConversions.KM_TO_MI.
*/
Location.distanceBetween(myTracksLocation2.getLatitude(), myTracksLocation2.getLongitude(),
myTracksLocation3.getLatitude(), myTracksLocation3.getLongitude(), results);
double distance2 = results[0] * UnitConversions.M_TO_KM * UnitConversions.KM_TO_MI;
assertEquals(distance1 + distance2, point[0]);
}
/**
* Tests the logic to get the values of time in
* {@link ChartFragment#fillDataPoint(Location, double[])}.
*/
public void testFillDataPoint_time() {
// By time
chartFragment.getChartView().setMode(ChartView.Mode.BY_TIME);
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
double[] point = fillDataPointTestHelper(myTracksLocation1);
assertEquals(0.0, point[0]);
long timeSpan = 222;
MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation();
myTracksLocation2.setTime(myTracksLocation1.getTime() + timeSpan);
point = fillDataPointTestHelper(myTracksLocation2);
assertEquals((double) timeSpan, point[0]);
}
/**
* Tests the logic to get the value of elevation in
* {@link ChartFragment#fillDataPoint(Location, double[])} by one and two
* points.
*/
public void testFillDataPoint_elevation() {
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
/*
* At first, clear old points of elevation, so give true to the second
* parameter. Then only one value INITIALLONGTITUDE in buffer.
*/
double[] point = fillDataPointTestHelper(myTracksLocation1);
assertEquals(TrackStubUtils.INITIAL_ALTITUDE, point[1]);
/*
* Send another value to buffer, now there are two values, INITIALALTITUDE
* and INITIALALTITUDE * 2.
*/
MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation();
myTracksLocation2.setAltitude(TrackStubUtils.INITIAL_ALTITUDE * 2);
point = fillDataPointTestHelper(myTracksLocation2);
assertEquals(
(TrackStubUtils.INITIAL_ALTITUDE + TrackStubUtils.INITIAL_ALTITUDE * 2) / 2.0, point[1]);
}
/**
* Tests the logic to get the value of speed in
* {@link ChartFragment#fillDataPoint(Location, double[])}. In this test,
* firstly remove all points in memory, and then fill in two points one by
* one. The speed values of these points are 129, 130.
*/
public void testFillDataPoint_speed() {
// Set max speed to make the speed of points are valid.
chartFragment.setTrackMaxSpeed(200.0);
/*
* At first, clear old points of speed, so give true to the second
* parameter. It will not be filled in to the speed buffer.
*/
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
myTracksLocation1.setSpeed(129);
double[] point = fillDataPointTestHelper(myTracksLocation1);
assertEquals(0.0, point[2]);
/*
* Tests the logic when both metricUnits and reportSpeed are true.This
* location will be filled into speed buffer.
*/
MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation();
/*
* Add a time span here to make sure the second point is valid, the value
* 222 here is doesn't matter.
*/
myTracksLocation2.setTime(myTracksLocation1.getTime() + 222);
myTracksLocation2.setSpeed(130);
point = fillDataPointTestHelper(myTracksLocation2);
assertEquals(130.0 * UnitConversions.MS_TO_KMH, point[2]);
}
/**
* Tests the logic to compute speed when use Imperial.
*/
public void testFillDataPoint_speedImperial() {
// Setups to use imperial.
chartFragment.setMetricUnits(false);
MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation();
myTracksLocation.setSpeed(132);
double[] point = fillDataPointTestHelper(myTracksLocation);
assertEquals(132.0 * UnitConversions.MS_TO_KMH * UnitConversions.KM_TO_MI, point[2]);
}
/**
* Tests the logic to get pace value when reportSpeed is false.
*/
public void testFillDataPoint_pace_nonZeroSpeed() {
// Setups reportSpeed to false.
chartFragment.setReportSpeed(false);
MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation();
myTracksLocation.setSpeed(134);
double[] point = fillDataPointTestHelper(myTracksLocation);
assertEquals(HOURS_PER_UNIT / (134.0 * UnitConversions.MS_TO_KMH), point[2]);
}
/**
* Tests the logic to get pace value when reportSpeed is false and average
* speed is zero.
*/
public void testFillDataPoint_pace_zeroSpeed() {
// Setups reportSpeed to false.
chartFragment.setReportSpeed(false);
MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation();
myTracksLocation.setSpeed(0);
double[] point = fillDataPointTestHelper(myTracksLocation);
assertEquals(0.0, point[2]);
}
/**
* Helper method to test fillDataPoint.
*
* @param location location to fill
* @return data of this location
*/
private double[] fillDataPointTestHelper(Location location) {
double[] point = new double[6];
chartFragment.fillDataPoint(location, point);
return point;
}
}
@@ -0,0 +1,138 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.ChartValueSeries.ZoomSettings;
import com.google.android.maps.mytracks.R;
import android.graphics.Paint.Style;
import android.test.AndroidTestCase;
/**
* @author Sandor Dornbush
*/
public class ChartValueSeriesTest extends AndroidTestCase {
private ChartValueSeries series;
@Override
protected void setUp() throws Exception {
series = new ChartValueSeries(getContext(),
R.color.elevation_fill,
R.color.elevation_border,
new ZoomSettings(5, new int[] {100}),
R.string.stat_elevation);
}
public void testInitialConditions() {
assertEquals(0, series.getInterval());
assertEquals(1, series.getMaxLabelLength());
assertEquals(0, series.getMin());
assertEquals(0, series.getMax());
assertEquals(0.0, series.getSpread());
assertEquals(Style.STROKE, series.getPaint().getStyle());
assertEquals(getContext().getString(R.string.stat_elevation),
series.getTitle());
assertTrue(series.isEnabled());
}
public void testEnabled() {
series.setEnabled(false);
assertFalse(series.isEnabled());
}
public void testSmallUpdates() {
series.update(0);
series.update(10);
series.updateDimension();
assertEquals(100, series.getInterval());
assertEquals(3, series.getMaxLabelLength());
assertEquals(0, series.getMin());
assertEquals(100, series.getMax());
assertEquals(100.0, series.getSpread());
}
public void testBigUpdates() {
series.update(0);
series.update(901);
series.updateDimension();
assertEquals(100, series.getInterval());
assertEquals(5, series.getMaxLabelLength());
assertEquals(0, series.getMin());
assertEquals(1000, series.getMax());
assertEquals(1000.0, series.getSpread());
}
public void testNotZeroBasedUpdates() {
series.update(500);
series.update(1401);
series.updateDimension();
assertEquals(100, series.getInterval());
assertEquals(5, series.getMaxLabelLength());
assertEquals(500, series.getMin());
assertEquals(1500, series.getMax());
assertEquals(1000.0, series.getSpread());
}
public void testZoomSettings_invalidArgs() {
try {
new ZoomSettings(0, new int[] {10, 50, 100});
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// OK.
}
try {
new ZoomSettings(1, null);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// OK.
}
try {
new ZoomSettings(1, new int[] {});
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// OK.
}
try {
new ZoomSettings(1, new int[] {1, 3, 2});
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// OK.
}
}
public void testZoomSettings_minAligned() {
ZoomSettings settings = new ZoomSettings(5, new int[] {10, 50, 100});
assertEquals(10, settings.calculateInterval(0, 15));
assertEquals(10, settings.calculateInterval(0, 50));
assertEquals(50, settings.calculateInterval(0, 111));
assertEquals(50, settings.calculateInterval(0, 250));
assertEquals(100, settings.calculateInterval(0, 251));
assertEquals(100, settings.calculateInterval(0, 10000));
}
public void testZoomSettings_minNotAligned() {
ZoomSettings settings = new ZoomSettings(5, new int[] {10, 50, 100});
assertEquals(50, settings.calculateInterval(5, 55));
assertEquals(10, settings.calculateInterval(10, 60));
assertEquals(50, settings.calculateInterval(7, 250));
assertEquals(100, settings.calculateInterval(7, 257));
assertEquals(100, settings.calculateInterval(11, 10000));
// A regression test.
settings = new ZoomSettings(5, new int[] {5, 10, 20});
assertEquals(10, settings.calculateInterval(-37.14, -11.89));
}
}
@@ -0,0 +1,176 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.maps.SingleColorTrackPathPainter;
import com.google.android.maps.MapView;
import android.graphics.Canvas;
import android.graphics.Path;
import android.location.Location;
import android.test.AndroidTestCase;
/**
* Tests for the MyTracks map overlay.
*
* @author Bartlomiej Niechwiej
* @author Vangelis S.
*/
public class MapOverlayTest extends AndroidTestCase {
private Canvas canvas;
private MockMyTracksOverlay myTracksOverlay;
private MapView mockView;
@Override
protected void setUp() throws Exception {
super.setUp();
canvas = new Canvas();
myTracksOverlay = new MockMyTracksOverlay(getContext());
// Enable drawing.
myTracksOverlay.setTrackDrawingEnabled(true);
// Set a TrackPathPainter with a MockPath.
myTracksOverlay.setTrackPathPainter(new SingleColorTrackPathPainter(getContext()) {
@Override
public Path newPath() {
return new MockPath();
}
});
mockView = null;
}
public void testAddLocation() throws Exception {
Location location = new Location("gps");
location.setLatitude(10);
location.setLongitude(20);
myTracksOverlay.addLocation(location);
assertEquals(1, myTracksOverlay.getNumLocations());
assertEquals(0, myTracksOverlay.getNumWaypoints());
location.setLatitude(20);
location.setLongitude(30);
myTracksOverlay.addLocation(location);
assertEquals(2, myTracksOverlay.getNumLocations());
assertEquals(0, myTracksOverlay.getNumWaypoints());
assertNull(myTracksOverlay.getTrackPathPainter().getLastPath());
// Draw and make sure that we don't lose any point.
myTracksOverlay.draw(canvas, mockView, false);
assertEquals(2, myTracksOverlay.getNumLocations());
assertEquals(0, myTracksOverlay.getNumWaypoints());
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath());
assertTrue(myTracksOverlay.getTrackPathPainter().getLastPath() instanceof MockPath);
MockPath path = (MockPath) myTracksOverlay.getTrackPathPainter().getLastPath();
assertEquals(2, path.totalPoints);
myTracksOverlay.draw(canvas, mockView, true);
assertEquals(2, myTracksOverlay.getNumLocations());
assertEquals(0, myTracksOverlay.getNumWaypoints());
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath());
}
public void testClearPoints() throws Exception {
Location location = new Location("gps");
location.setLatitude(10);
location.setLongitude(20);
myTracksOverlay.addLocation(location);
assertEquals(1, myTracksOverlay.getNumLocations());
myTracksOverlay.clearPoints();
assertEquals(0, myTracksOverlay.getNumLocations());
// Same after drawing on canvas.
final int locations = 100;
for (int i = 0; i < locations; ++i) {
myTracksOverlay.addLocation(location);
}
assertEquals(locations, myTracksOverlay.getNumLocations());
myTracksOverlay.draw(canvas, mockView, false);
myTracksOverlay.draw(canvas, mockView, true);
myTracksOverlay.clearPoints();
assertEquals(0, myTracksOverlay.getNumLocations());
}
public void testAddWaypoint() throws Exception {
Location location = new Location("gps");
location.setLatitude(10);
location.setLongitude(20);
Waypoint waypoint = new Waypoint();
waypoint.setLocation(location);
myTracksOverlay.addWaypoint(waypoint);
assertEquals(1, myTracksOverlay.getNumWaypoints());
assertEquals(0, myTracksOverlay.getNumLocations());
assertNull(myTracksOverlay.getTrackPathPainter().getLastPath());
final int waypoints = 10;
for (int i = 0; i < waypoints; ++i) {
waypoint = new Waypoint();
waypoint.setLocation(location);
myTracksOverlay.addWaypoint(waypoint);
}
assertEquals(1 + waypoints, myTracksOverlay.getNumWaypoints());
assertEquals(0, myTracksOverlay.getNumLocations());
assertNull(myTracksOverlay.getTrackPathPainter().getLastPath());
}
public void testClearWaypoints() throws Exception {
Location location = new Location("gps");
location.setLatitude(10);
location.setLongitude(20);
Waypoint waypoint = new Waypoint();
waypoint.setLocation(location);
myTracksOverlay.addWaypoint(waypoint);
assertEquals(1, myTracksOverlay.getNumWaypoints());
myTracksOverlay.clearWaypoints();
assertEquals(0, myTracksOverlay.getNumWaypoints());
}
public void testDrawing() {
Location location = new Location("gps");
location.setLatitude(10);
for (int i = 0; i < 40; ++i) {
location.setLongitude(20 + i);
Waypoint waypoint = new Waypoint();
waypoint.setLocation(location);
myTracksOverlay.addWaypoint(waypoint);
}
for (int i = 0; i < 100; ++i) {
location = new Location("gps");
location.setLatitude(20 + i / 2);
location.setLongitude(150 - i);
myTracksOverlay.addLocation(location);
}
// Shadow.
myTracksOverlay.draw(canvas, mockView, true);
// We don't expect to do anything if
assertNull(myTracksOverlay.getTrackPathPainter().getLastPath());
assertEquals(40, myTracksOverlay.getNumWaypoints());
assertEquals(100, myTracksOverlay.getNumLocations());
// No shadow.
myTracksOverlay.draw(canvas, mockView, false);
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath());
assertTrue(myTracksOverlay.getTrackPathPainter().getLastPath() instanceof MockPath);
MockPath path = (MockPath) myTracksOverlay.getTrackPathPainter().getLastPath();
assertEquals(40, myTracksOverlay.getNumWaypoints());
assertEquals(100, myTracksOverlay.getNumLocations());
assertEquals(100, path.totalPoints);
// TODO: Check the points from the path (and the segments).
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.maps.MapView;
import com.google.android.maps.Projection;
import android.content.Context;
import android.graphics.Rect;
/**
* Elements for Tests for the MyTracks map overlay.
*
* @author Bartlomiej Niechwiej
* @author Vangelis S.
*
* A mock version of {@code MapOverlay} that does not use
* {@class MapView}.
*/
public class MockMyTracksOverlay extends MapOverlay {
private Projection mockProjection;
public MockMyTracksOverlay(Context context) {
super(context);
mockProjection = new MockProjection();
}
@Override
public Projection getMapProjection(MapView mapView) {
return mockProjection;
}
@Override
public Rect getMapViewRect(MapView mapView) {
return new Rect(0, 0, 100, 100);
}
}
@@ -0,0 +1,60 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import android.graphics.Path;
import android.graphics.PointF;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import junit.framework.Assert;
/**
* Elements for Tests for the MyTracks map overlay.
*
* @author Bartlomiej Niechwiej
* @author Vangelis S.
*
* A mock class that intercepts {@code Path}'s and records calls to
* {@code #moveTo()} and {@code #lineTo()}.
*/
public class MockPath extends Path {
/** A list of disjoined path segments. */
public final List<List<PointF>> segments = new LinkedList<List<PointF>>();
/** The total number of points in this path. */
public int totalPoints;
private List<PointF> currentSegment;
@Override
public void lineTo(float x, float y) {
super.lineTo(x, y);
Assert.assertNotNull(currentSegment);
currentSegment.add(new PointF(x, y));
totalPoints++;
}
@Override
public void moveTo(float x, float y) {
super.moveTo(x, y);
segments.add(currentSegment =
new ArrayList<PointF>(Arrays.asList(new PointF(x, y))));
totalPoints++;
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.Projection;
import android.graphics.Point;
/**
* Elements for Tests for the MyTracks map overlay.
*
* @author Bartlomiej Niechwiej
* @author Vangelis S.
*
* A mock {@code Projection} that acts as the identity matrix.
*/
public class MockProjection implements Projection {
@Override
public Point toPixels(GeoPoint in, Point out) {
return out;
}
@Override
public float metersToEquatorPixels(float meters) {
return meters;
}
@Override
public GeoPoint fromPixels(int x, int y) {
return new GeoPoint(y, x);
}
}
@@ -0,0 +1,190 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.services.ServiceUtils;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.test.ActivityInstrumentationTestCase2;
import java.io.File;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* A unit test for {@link TrackDetailActivity}.
*
* @author Bartlomiej Niechwiej
*/
public class TrackDetailActivityTest extends ActivityInstrumentationTestCase2<TrackDetailActivity>{
private SharedPreferences sharedPreferences;
private TrackRecordingServiceConnection serviceConnection;
public TrackDetailActivityTest() {
super(TrackDetailActivity.class);
}
@Override
protected void tearDown() throws Exception {
clearSelectedAndRecordingTracks();
waitForIdle();
super.tearDown();
}
public void testInitialization_mainAction() {
// Make sure we can start MyTracks and the activity doesn't start recording.
assertInitialized();
// Check if not recording.
assertFalse(isRecording());
assertEquals(-1, getRecordingTrackId());
}
public void testInitialization_viewActionWithNoData() {
// Simulate start with ACTION_VIEW intent.
Intent startIntent = new Intent();
startIntent.setAction(Intent.ACTION_VIEW);
setActivityIntent(startIntent);
assertInitialized();
// Check if not recording.
assertFalse(isRecording());
assertEquals(-1, getRecordingTrackId());
}
public void testInitialization_viewActionWithValidData() throws Exception {
// Simulate start with ACTION_VIEW intent.
Intent startIntent = new Intent();
startIntent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(File.createTempFile("valid", ".gpx", getActivity().getFilesDir()));
// TODO: Add a valid GPX.
startIntent.setData(uri);
setActivityIntent(startIntent);
assertInitialized();
// Check if not recording.
assertFalse(isRecording());
assertEquals(-1, getRecordingTrackId());
// TODO: Finish this test.
}
public void testInitialization_viewActionWithInvalidData() throws Exception {
// Simulate start with ACTION_VIEW intent.
Intent startIntent = new Intent();
startIntent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(File.createTempFile("invalid", ".gpx", getActivity().getFilesDir()));
startIntent.setData(uri);
setActivityIntent(startIntent);
assertInitialized();
// Check if not recording.
assertFalse(isRecording());
assertEquals(-1, getRecordingTrackId());
// TODO: Finish this test.
}
private void assertInitialized() {
assertNotNull(getActivity());
serviceConnection = new TrackRecordingServiceConnection(getActivity(), null);
}
/**
* Waits until the UI thread becomes idle.
*/
private void waitForIdle() throws InterruptedException {
// Note: We can't use getInstrumentation().waitForIdleSync() here.
final Object semaphore = new Object();
synchronized (semaphore) {
final AtomicBoolean isIdle = new AtomicBoolean();
getInstrumentation().waitForIdle(new Runnable() {
@Override
public void run() {
synchronized (semaphore) {
isIdle.set(true);
semaphore.notify();
}
}
});
while (!isIdle.get()) {
semaphore.wait();
}
}
}
/**
* Clears {selected,recording}TrackId in the {@link #getSharedPreferences()}.
*/
private void clearSelectedAndRecordingTracks() {
Editor editor = getSharedPreferences().edit();
editor.putLong(getActivity().getString(R.string.selected_track_key), -1);
editor.putLong(getActivity().getString(R.string.recording_track_key), -1);
editor.clear();
editor.apply();
}
/**
* Waits until the recording state changes to the given status.
*
* @param timeout the maximum time to wait, in milliseconds.
* @param isRecording the final status to await.
* @return the recording track ID.
*/
private long awaitRecordingStatus(long timeout, boolean isRecording)
throws TimeoutException, InterruptedException {
long startTime = System.nanoTime();
while (isRecording() != isRecording) {
if (System.nanoTime() - startTime > timeout * 1000000) {
throw new TimeoutException("Timeout while waiting for recording!");
}
Thread.sleep(20);
}
waitForIdle();
assertEquals(isRecording, isRecording());
return getRecordingTrackId();
}
private long getRecordingTrackId() {
return getSharedPreferences().getLong(getActivity().getString(R.string.recording_track_key), -1);
}
private SharedPreferences getSharedPreferences() {
if (sharedPreferences == null) {
sharedPreferences = getActivity().getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
}
return sharedPreferences;
}
private boolean isRecording() {
return ServiceUtils.isRecording(getActivity(),
serviceConnection.getServiceIfBound(), getSharedPreferences());
}
}
@@ -0,0 +1,90 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.content.Track;
import android.location.Location;
/**
* Commons utilities for creating stubs of track, location. The class will be
* enriched if needs more similar stubs for test.
*
* @author Youtao Liu
*/
public class TrackStubUtils {
static final String LOCATION_PROVIDER = "gps";
public static final double INITIAL_LATITUDE = 22;
public static final double INITIAL_LONGITUDE = 22;
public static final double INITIAL_ALTITUDE = 22;
static final float INITIAL_ACCURACY = 5;
static final float INITIAL_SPEED = 10;
static final float INITIAL_BEARING = 3.0f;
// Used to change the value of latitude, longitude, and altitude.
static final double DIFFERENCE = 0.01;
/**
* Gets a a {@link Track} stub with specified number of locations.
*
* @param numberOfLocations the number of locations for the track
* @return a track stub.
*/
public static Track createTrack(int numberOfLocations) {
Track track = new Track();
for (int i = 0; i < numberOfLocations; i++) {
track.addLocation(createMyTracksLocation(INITIAL_LATITUDE + i * DIFFERENCE, INITIAL_LONGITUDE
+ i * DIFFERENCE, INITIAL_ALTITUDE + i * DIFFERENCE));
}
return track;
}
/**
* Create a MyTracks location with default values.
*
* @return a track stub.
*/
public static MyTracksLocation createMyTracksLocation() {
return createMyTracksLocation(INITIAL_LATITUDE, INITIAL_LONGITUDE, INITIAL_ALTITUDE);
}
/**
* Creates a {@link MyTracksLocation} stub with specified values.
*
* @return a MyTracksLocation stub.
*/
public static MyTracksLocation createMyTracksLocation(double latitude, double longitude,
double altitude) {
// Initial Location
Location loc = new Location(LOCATION_PROVIDER);
loc.setLatitude(latitude);
loc.setLongitude(longitude);
loc.setAltitude(altitude);
loc.setAccuracy(INITIAL_ACCURACY);
loc.setSpeed(INITIAL_SPEED);
loc.setTime(System.currentTimeMillis());
loc.setBearing(INITIAL_BEARING);
SensorDataSet sd = SensorDataSet.newBuilder().build();
MyTracksLocation myTracksLocation = new MyTracksLocation(loc, sd);
return myTracksLocation;
}
}
@@ -0,0 +1,209 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.maps.mytracks.R;
import android.test.AndroidTestCase;
import android.util.Pair;
/**
* Tests for {@link DescriptionGeneratorImpl}.
*
* @author Jimmy Shih
*/
public class DescriptionGeneratorImplTest extends AndroidTestCase {
private DescriptionGeneratorImpl descriptionGenerator;
@Override
protected void setUp() throws Exception {
descriptionGenerator = new DescriptionGeneratorImpl(getContext());
}
/**
* Tests {@link DescriptionGeneratorImpl#generateTrackDescription(Track,
* java.util.Vector, java.util.Vector)}.
*/
public void testGenerateTrackDescription() {
Track track = new Track();
TripStatistics stats = new TripStatistics();
stats.setTotalDistance(20000);
stats.setTotalTime(600000);
stats.setMovingTime(300000);
stats.setMaxSpeed(100);
stats.setMaxElevation(550);
stats.setMinElevation(-500);
stats.setTotalElevationGain(6000);
stats.setMaxGrade(0.42);
stats.setMinGrade(0.11);
stats.setStartTime(1288721514000L);
track.setStatistics(stats);
track.setCategory("hiking");
String expected = "Created by"
+ " <a href='http://www.google.com/mobile/mytracks'>My Tracks</a> on Android.<p>"
+ "Total distance: 20.00 km (12.4 mi)<br>"
+ "Total time: 10:00<br>"
+ "Moving time: 05:00<br>"
+ "Average speed: 120.00 km/h (74.6 mi/h)<br>"
+ "Average moving speed: 240.00 km/h (149.1 mi/h)<br>"
+ "Max speed: 360.00 km/h (223.7 mi/h)<br>"
+ "Average pace: 0.50 min/km (0.8 min/mi)<br>"
+ "Average moving pace: 0.25 min/km (0.4 min/mi)<br>"
+ "Min pace: 0.17 min/km (0.3 min/mi)<br>"
+ "Max elevation: 550 m (1804 ft)<br>"
+ "Min elevation: -500 m (-1640 ft)<br>"
+ "Elevation gain: 6000 m (19685 ft)<br>"
+ "Max grade: 42 %<br>"
+ "Min grade: 11 %<br>"
+ "Recorded: 11/2/2010 11:11 AM<br>"
+ "Activity type: hiking<br>";
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, null, null));
}
/**
* Tests {@link DescriptionGeneratorImpl#generateWaypointDescription(Waypoint)}.
*/
public void testGenerateWaypointDescription() {
Waypoint waypoint = new Waypoint();
TripStatistics stats = new TripStatistics();
stats.setTotalDistance(20000);
stats.setTotalTime(600000);
stats.setMovingTime(300000);
stats.setMaxSpeed(100);
stats.setMaxElevation(550);
stats.setMinElevation(-500);
stats.setTotalElevationGain(6000);
stats.setMaxGrade(0.42);
stats.setMinGrade(0.11);
stats.setStartTime(1288721514000L);
waypoint.setStatistics(stats);
String expected = "Total distance: 20.00 km (12.4 mi)\n"
+ "Total time: 10:00\n"
+ "Moving time: 05:00\n"
+ "Average speed: 120.00 km/h (74.6 mi/h)\n"
+ "Average moving speed: 240.00 km/h (149.1 mi/h)\n"
+ "Max speed: 360.00 km/h (223.7 mi/h)\n"
+ "Average pace: 0.50 min/km (0.8 min/mi)\n"
+ "Average moving pace: 0.25 min/km (0.4 min/mi)\n"
+ "Min pace: 0.17 min/km (0.3 min/mi)\n"
+ "Max elevation: 550 m (1804 ft)\n"
+ "Min elevation: -500 m (-1640 ft)\n"
+ "Elevation gain: 6000 m (19685 ft)\n"
+ "Max grade: 42 %\n"
+ "Min grade: 11 %\n"
+ "Recorded: 11/2/2010 11:11 AM\n";
assertEquals(expected, descriptionGenerator.generateWaypointDescription(waypoint));
}
/**
* Tests {@link DescriptionGeneratorImpl#writeDistance(double, StringBuilder,
* int, String)}.
*/
public void testWriteDistance() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeDistance(1100, builder, R.string.description_total_distance, "<br>");
assertEquals("Total distance: 1.10 km (0.7 mi)<br>", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writeTime(long, StringBuilder, int,
* String)}.
*/
public void testWriteTime() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeTime(1000, builder, R.string.description_total_time, "<br>");
assertEquals("Total time: 00:01<br>", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writeSpeed(double, StringBuilder,
* int, String)}.
*/
public void testWriteSpeed() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeSpeed(1.1, builder, R.string.description_average_speed, "\n");
assertEquals("Average speed: 3.96 km/h (2.5 mi/h)\n", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writeElevation(double, StringBuilder,
* int, String)}.
*/
public void testWriteElevation() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeElevation(4.2, builder, R.string.description_min_elevation, "<br>");
assertEquals("Min elevation: 4 m (14 ft)<br>", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writePace(Pair, StringBuilder, int,
* String)}.
*/
public void testWritePace() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writePace(
new Pair<Double, Double>(1.1, 2.2), builder, R.string.description_average_pace, "\n");
assertEquals("Average pace: 54.55 min/km (27.3 min/mi)\n", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writeGrade(double, StringBuilder,
* int, String)}.
*/
public void testWriteGrade() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeGrade(.042, builder, R.string.description_max_grade, "<br>");
assertEquals("Max grade: 4 %<br>", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writeGrade(double, StringBuilder,
* int, String)} with a NaN.
*/
public void testWriteGrade_nan() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeGrade(Double.NaN, builder, R.string.description_max_grade, "<br>");
assertEquals("Max grade: 0 %<br>", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#writeGrade(double, StringBuilder,
* int, String)} with an infinite number.
*/
public void testWriteGrade_infinite() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeGrade(
Double.POSITIVE_INFINITY, builder, R.string.description_max_grade, "<br>");
assertEquals("Max grade: 0 %<br>", builder.toString());
}
/**
* Tests {@link DescriptionGeneratorImpl#getPace(double)}.
*/
public void testGetPace() {
assertEquals(12.0, descriptionGenerator.getPace(5));
}
/**
* Tests {@link DescriptionGeneratorImpl#getPace(double)} with zero speed.
*/
public void testGetPace_zero() {
assertEquals(0.0, descriptionGenerator.getPace(0));
}
}
@@ -0,0 +1,171 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationFactory;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
import android.content.Context;
import android.location.Location;
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.test.mock.MockContentResolver;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A unit test for {@link MyTracksProviderUtilsImpl}.
*
* @author Bartlomiej Niechwiej
*/
public class MyTracksProviderUtilsImplTest extends AndroidTestCase {
private Context context;
private MyTracksProviderUtils providerUtils;
@Override
protected void setUp() throws Exception {
super.setUp();
MockContentResolver mockContentResolver = new MockContentResolver();
RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
getContext(), getContext(), "test.");
context = new MockContext(mockContentResolver, targetContext);
MyTracksProvider provider = new MyTracksProvider();
provider.attachInfo(context, null);
mockContentResolver.addProvider(MyTracksProviderUtils.AUTHORITY, provider);
setContext(context);
providerUtils = MyTracksProviderUtils.Factory.get(context);
}
public void testLocationIterator_noPoints() {
testIterator(1, 0, 1, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
}
public void testLocationIterator_customFactory() {
final Location location = new Location("test_location");
final AtomicInteger counter = new AtomicInteger();
testIterator(1, 15, 4, false, new LocationFactory() {
@Override
public Location createLocation() {
counter.incrementAndGet();
return location;
}
});
// Make sure we were called exactly as many times as we had track points.
assertEquals(15, counter.get());
}
public void testLocationIterator_nullFactory() {
try {
testIterator(1, 15, 4, false, null);
fail("Expecting IllegalArgumentException");
} catch (IllegalArgumentException e) {
// Expected.
}
}
public void testLocationIterator_noBatchAscending() {
testIterator(1, 50, 100, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 50, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
}
public void testLocationIterator_noBatchDescending() {
testIterator(1, 50, 100, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 50, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
}
public void testLocationIterator_batchAscending() {
testIterator(1, 50, 11, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 25, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
}
public void testLocationIterator_batchDescending() {
testIterator(1, 50, 11, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 25, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
}
public void testLocationIterator_largeTrack() {
testIterator(1, 20000, 2000, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
}
private List<Location> testIterator(long trackId, int numPoints, int batchSize,
boolean descending, LocationFactory locationFactory) {
long lastPointId = initializeTrack(trackId, numPoints);
((MyTracksProviderUtilsImpl) providerUtils).setDefaultCursorBatchSize(batchSize);
List<Location> locations = new ArrayList<Location>(numPoints);
LocationIterator it = providerUtils.getLocationIterator(trackId, -1, descending, locationFactory);
try {
while (it.hasNext()) {
Location loc = it.next();
assertNotNull(loc);
locations.add(loc);
// Make sure the IDs are returned in the right order.
assertEquals(descending ? lastPointId - locations.size() + 1
: lastPointId - numPoints + locations.size(), it.getLocationId());
}
assertEquals(numPoints, locations.size());
} finally {
it.close();
}
return locations;
}
private long initializeTrack(long id, int numPoints) {
Track track = new Track();
track.setId(id);
track.setName("Test: " + id);
track.setNumberOfPoints(numPoints);
providerUtils.insertTrack(track);
track = providerUtils.getTrack(id);
assertNotNull(track);
Location[] locations = new Location[numPoints];
for (int i = 0; i < numPoints; ++i) {
Location loc = new Location("test");
loc.setLatitude(37.0 + (double) i / 10000.0);
loc.setLongitude(57.0 - (double) i / 10000.0);
loc.setAccuracy((float) i / 100.0f);
loc.setAltitude(i * 2.5);
locations[i] = loc;
}
providerUtils.bulkInsertTrackPoints(locations, numPoints, id);
// Load all inserted locations.
long lastPointId = -1;
int counter = 0;
LocationIterator it = providerUtils.getLocationIterator(id, -1, false,
MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
try {
while (it.hasNext()) {
it.next();
lastPointId = it.getLocationId();
counter++;
}
} finally {
it.close();
}
assertTrue(numPoints == 0 || lastPointId > 0);
assertEquals(numPoints, track.getNumberOfPoints());
assertEquals(numPoints, counter);
return lastPointId;
}
}
@@ -0,0 +1,326 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.content.SearchEngine.ScoredResult;
import com.google.android.apps.mytracks.content.SearchEngine.SearchQuery;
import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
import com.google.android.apps.mytracks.stats.TripStatistics;
import android.content.ContentUris;
import android.location.Location;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.test.mock.MockContentResolver;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Tests for {@link SearchEngine}.
* These are not meant to be quality tests, but instead feature-by-feature tests
* (in other words, they don't test the mixing of different score boostings, just
* each boosting separately)
*
* @author Rodrigo Damazio
*/
public class SearchEngineTest extends AndroidTestCase {
private static final Location HERE = new Location("gps");
private static final long NOW = 1234567890000L; // After OLDEST_ALLOWED_TIMESTAMP
private MyTracksProviderUtils providerUtils;
private SearchEngine engine;
@Override
protected void setUp() throws Exception {
super.setUp();
MockContentResolver mockContentResolver = new MockContentResolver();
RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
getContext(), getContext(), "test.");
MockContext context = new MockContext(mockContentResolver, targetContext);
MyTracksProvider provider = new MyTracksProvider();
provider.attachInfo(context, null);
mockContentResolver.addProvider(MyTracksProviderUtils.AUTHORITY, provider);
setContext(context);
providerUtils = MyTracksProviderUtils.Factory.get(context);
engine = new SearchEngine(providerUtils);
}
@Override
protected void tearDown() throws Exception {
providerUtils.deleteAllTracks();
super.tearDown();
}
private long insertTrack(String title, String description, String category, double distance, long hoursAgo) {
Track track = new Track();
track.setName(title);
track.setDescription(description);
track.setCategory(category);
TripStatistics stats = track.getStatistics();
if (hoursAgo > 0) {
// Started twice hoursAgo, so the average time is hoursAgo.
stats.setStartTime(NOW - hoursAgo * 1000L * 60L * 60L * 2);
stats.setStopTime(NOW);
}
int latitude = (int) ((HERE.getLatitude() + distance) * 1E6);
int longitude = (int) ((HERE.getLongitude() + distance) * 1E6);
stats.setBounds(latitude, longitude, latitude, longitude);
Uri uri = providerUtils.insertTrack(track);
return ContentUris.parseId(uri);
}
private long insertTrack(String title, String description, String category) {
return insertTrack(title, description, category, 0, -1);
}
private long insertTrack(String title, double distance) {
return insertTrack(title, "", "", distance, -1);
}
private long insertTrack(String title, long hoursAgo) {
return insertTrack(title, "", "", 0.0, hoursAgo);
}
private long insertWaypoint(String title, String description, String category, double distance, long hoursAgo, long trackId) {
Waypoint waypoint = new Waypoint();
waypoint.setName(title);
waypoint.setDescription(description);
waypoint.setCategory(category);
waypoint.setTrackId(trackId);
Location location = new Location(HERE);
location.setLatitude(location.getLatitude() + distance);
location.setLongitude(location.getLongitude() + distance);
if (hoursAgo >= 0) {
location.setTime(NOW - hoursAgo * 1000L * 60L * 60L);
}
waypoint.setLocation(location);
Uri uri = providerUtils.insertWaypoint(waypoint);
return ContentUris.parseId(uri);
}
private long insertWaypoint(String title, String description, String category) {
return insertWaypoint(title, description, category, 0.0, -1, -1);
}
private long insertWaypoint(String title, double distance) {
return insertWaypoint(title, "", "", distance, -1, -1);
}
private long insertWaypoint(String title, long hoursAgo) {
return insertWaypoint(title, "", "", 0.0, hoursAgo, -1);
}
private long insertWaypoint(String title, long hoursAgo, long trackId) {
return insertWaypoint(title, "", "", 0.0, hoursAgo, trackId);
}
public void testSearchText() {
// Insert 7 tracks (purposefully out of result order):
// - one which won't match
// - one which will match the description
// - one which will match the category
// - one which will match the title
// - one which will match in title and category
// - one which will match in title and description
// - one which will match in all fields
insertTrack("bb", "cc", "dd");
long descriptionMatchId = insertTrack("bb", "aa", "cc");
long categoryMatchId = insertTrack("bb", "cc", "aa");
long titleMatchId = insertTrack("aa", "bb", "cc");
long titleCategoryMatchId = insertTrack("aa", "bb", "ca");
long titleDescriptionMatchId = insertTrack("aa", "ba", "cc");
long allMatchId = insertTrack("aa", "ba", "ca");
SearchQuery query = new SearchQuery("a", null, -1, NOW);
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
// Title > Description > Category.
assertTrackResults(results,
allMatchId, titleDescriptionMatchId, titleCategoryMatchId, titleMatchId, descriptionMatchId,
categoryMatchId);
}
public void testSearchWaypointText() {
// Insert 7 waypoints (purposefully out of result order):
// - one which won't match
// - one which will match the description
// - one which will match the category
// - one which will match the title
// - one which will match in title and category
// - one which will match in title and description
// - one which will match in all fields
insertWaypoint("bb", "cc", "dd");
long descriptionMatchId = insertWaypoint("bb", "aa", "cc");
long categoryMatchId = insertWaypoint("bb", "cc", "aa");
long titleMatchId = insertWaypoint("aa", "bb", "cc");
long titleCategoryMatchId = insertWaypoint("aa", "bb", "ca");
long titleDescriptionMatchId = insertWaypoint("aa", "ba", "cc");
long allMatchId = insertWaypoint("aa", "ba", "ca");
SearchQuery query = new SearchQuery("a", null, -1, NOW);
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
// Title > Description > Category.
assertWaypointResults(results,
allMatchId, titleDescriptionMatchId, titleCategoryMatchId, titleMatchId, descriptionMatchId,
categoryMatchId);
}
public void testSearchMixedText() {
// Insert 5 entries (purposefully out of result order):
// - one waypoint which will match by description
// - one waypoint which won't match
// - one waypoint which will match by title
// - one track which won't match
// - one track which will match by title
long descriptionWaypointId = insertWaypoint("bb", "aa", "cc");
insertWaypoint("bb", "cc", "dd");
long titleWaypointId = insertWaypoint("aa", "bb", "cc");
insertTrack("bb", "cc", "dd");
long trackId = insertTrack("aa", "bb", "cc");
SearchQuery query = new SearchQuery("a", null, -1, NOW);
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
// Title > Description > Category.
assertEquals(results.toString(), 3, results.size());
assertTrackResult(trackId, results.get(0));
assertWaypointResult(titleWaypointId, results.get(1));
assertWaypointResult(descriptionWaypointId, results.get(2));
}
public void testSearchTrackDistance() {
// All results match text, but they're at difference distances from the user.
long farFarAwayId = insertTrack("aa", 0.3);
long nearId = insertTrack("ab", 0.1);
long farId = insertTrack("ac", 0.2);
SearchQuery query = new SearchQuery("a", HERE, -1, NOW);
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
// Distance order.
assertTrackResults(results, nearId, farId, farFarAwayId);
}
public void testSearchWaypointDistance() {
// All results match text, but they're at difference distances from the user.
long farFarAwayId = insertWaypoint("aa", 0.3);
long nearId = insertWaypoint("ab", 0.1);
long farId = insertWaypoint("ac", 0.2);
SearchQuery query = new SearchQuery("a", HERE, -1, NOW);
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
// Distance order.
assertWaypointResults(results, nearId, farId, farFarAwayId);
}
public void testSearchTrackRecent() {
// All results match text, but they're were recorded at different times.
long oldestId = insertTrack("aa", 3);
long recentId = insertTrack("ab", 1);
long oldId = insertTrack("ac", 2);
SearchQuery query = new SearchQuery("a", null, -1, NOW);
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
// Reverse time order.
assertTrackResults(results, recentId, oldId, oldestId);
}
public void testSearchWaypointRecent() {
// All results match text, but they're were recorded at different times.
long oldestId = insertWaypoint("aa", 2);
long recentId = insertWaypoint("ab", 0);
long oldId = insertWaypoint("ac", 1);
SearchQuery query = new SearchQuery("a", null, -1, NOW);
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
// Reverse time order.
assertWaypointResults(results, recentId, oldId, oldestId);
}
public void testSearchCurrentTrack() {
// All results match text, but one of them is the current track.
long currentId = insertTrack("ab", 1);
long otherId = insertTrack("aa", 1);
SearchQuery query = new SearchQuery("a", null, currentId, NOW);
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
// Current track should be demoted.
assertTrackResults(results, otherId, currentId);
}
public void testSearchCurrentTrackWaypoint() {
// All results match text, but one of them is in the current track.
long otherId = insertWaypoint("aa", 1, 456);
long currentId = insertWaypoint("ab", 1, 123);
SearchQuery query = new SearchQuery("a", null, 123, NOW);
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
// Waypoint in current track should be promoted.
assertWaypointResults(results, currentId, otherId);
}
private void assertTrackResult(long trackId, ScoredResult result) {
assertNotNull("Not a track", result.track);
assertNull("Ambiguous result", result.waypoint);
assertEquals(trackId, result.track.getId());
}
private void assertTrackResults(List<ScoredResult> results, long... trackIds) {
String errMsg = "Expected IDs=" + Arrays.toString(trackIds) + "; results=" + results;
assertEquals(results.size(), trackIds.length);
for (int i = 0; i < results.size(); i++) {
ScoredResult result = results.get(i);
assertNotNull(errMsg, result.track);
assertNull(errMsg, result.waypoint);
assertEquals(errMsg, trackIds[i], result.track.getId());
}
}
private void assertWaypointResult(long waypointId, ScoredResult result) {
assertNotNull("Not a waypoint", result.waypoint);
assertNull("Ambiguous result", result.track);
assertEquals(waypointId, result.waypoint.getId());
}
private void assertWaypointResults(List<ScoredResult> results, long... waypointIds) {
String errMsg = "Expected IDs=" + Arrays.toString(waypointIds) + "; results=" + results;
assertEquals(results.size(), waypointIds.length);
for (int i = 0; i < results.size(); i++) {
ScoredResult result = results.get(i);
assertNotNull(errMsg, result.waypoint);
assertNull(errMsg, result.track);
assertEquals(errMsg, waypointIds[i], result.waypoint.getId());
}
}
}
@@ -0,0 +1,876 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.content;
import static com.google.android.testing.mocking.AndroidMock.anyInt;
import static com.google.android.testing.mocking.AndroidMock.capture;
import static com.google.android.testing.mocking.AndroidMock.eq;
import static com.google.android.testing.mocking.AndroidMock.expect;
import static com.google.android.testing.mocking.AndroidMock.isA;
import static com.google.android.testing.mocking.AndroidMock.leq;
import static com.google.android.testing.mocking.AndroidMock.same;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationFactory;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
import com.google.android.apps.mytracks.content.TrackDataListener.ProviderState;
import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
import com.google.android.maps.mytracks.R;
import com.google.android.testing.mocking.AndroidMock;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.location.Location;
import android.location.LocationListener;
import android.provider.BaseColumns;
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.test.mock.MockContentResolver;
import java.lang.reflect.Constructor;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import org.easymock.Capture;
import org.easymock.IAnswer;
/**
* Tests for {@link TrackDataHub}.
*
* @author Rodrigo Damazio
*/
public class TrackDataHubTest extends AndroidTestCase {
private static final long TRACK_ID = 42L;
private static final int TARGET_POINTS = 50;
private MyTracksProviderUtils providerUtils;
private TrackDataHub hub;
private TrackDataListeners listeners;
private DataSourcesWrapper dataSources;
private SharedPreferences prefs;
private TrackDataListener listener1;
private TrackDataListener listener2;
private Capture<OnSharedPreferenceChangeListener> preferenceListenerCapture =
new Capture<SharedPreferences.OnSharedPreferenceChangeListener>();
private MockContext context;
private float declination;
@Override
protected void setUp() throws Exception {
super.setUp();
MockContentResolver mockContentResolver = new MockContentResolver();
RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
getContext(), getContext(), "test.");
context = new MockContext(mockContentResolver, targetContext);
prefs = context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
providerUtils = AndroidMock.createMock("providerUtils", MyTracksProviderUtils.class);
dataSources = AndroidMock.createNiceMock("dataSources", DataSourcesWrapper.class);
listeners = new TrackDataListeners();
hub = new TrackDataHub(context, listeners, prefs, providerUtils, TARGET_POINTS) {
@Override
protected DataSourcesWrapper newDataSources() {
return dataSources;
}
@Override
protected void runInListenerThread(Runnable runnable) {
// Run everything in the same thread.
runnable.run();
}
@Override
protected float getDeclinationFor(Location location, long timestamp) {
return declination;
}
};
listener1 = AndroidMock.createStrictMock("listener1", TrackDataListener.class);
listener2 = AndroidMock.createStrictMock("listener2", TrackDataListener.class);
}
@Override
protected void tearDown() throws Exception {
AndroidMock.reset(dataSources);
// Expect everything to be unregistered.
if (preferenceListenerCapture.hasCaptured()) {
dataSources.unregisterOnSharedPreferenceChangeListener(preferenceListenerCapture.getValue());
}
dataSources.removeLocationUpdates(isA(LocationListener.class));
dataSources.unregisterSensorListener(isA(SensorEventListener.class));
dataSources.unregisterContentObserver(isA(ContentObserver.class));
AndroidMock.expectLastCall().times(3);
AndroidMock.replay(dataSources);
hub.stop();
hub = null;
super.tearDown();
}
public void testTrackListen() {
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
Track track = new Track();
prefs.edit().putLong("recordingTrack", TRACK_ID)
.putLong("selectedTrack", TRACK_ID).apply();
expect(providerUtils.getTrack(TRACK_ID)).andStubReturn(track);
expectStart();
dataSources.registerContentObserver(
eq(TracksColumns.CONTENT_URI), eq(false), capture(observerCapture));
// Expect the initial loading.
// Both listeners (registered before and after start) should get the same data.
listener1.onTrackUpdated(track);
listener2.onTrackUpdated(track);
replay();
hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.TRACK_UPDATES));
hub.start();
hub.registerTrackDataListener(listener2, EnumSet.of(ListenerDataType.TRACK_UPDATES));
verifyAndReset();
ContentObserver observer = observerCapture.getValue();
expect(providerUtils.getTrack(TRACK_ID)).andStubReturn(track);
// Now expect an update.
listener1.onTrackUpdated(track);
listener2.onTrackUpdated(track);
replay();
observer.onChange(false);
verifyAndReset();
// Unregister one, get another update.
expect(providerUtils.getTrack(TRACK_ID)).andStubReturn(track);
listener2.onTrackUpdated(track);
replay();
hub.unregisterTrackDataListener(listener1);
observer.onChange(false);
verifyAndReset();
// Unregister the other, expect internal unregistration
dataSources.unregisterContentObserver(observer);
replay();
hub.unregisterTrackDataListener(listener2);
observer.onChange(false);
verifyAndReset();
}
private static class FixedSizeCursorAnswer implements IAnswer<Cursor> {
private final int size;
public FixedSizeCursorAnswer(int size) {
this.size = size;
}
@Override
public Cursor answer() throws Throwable {
MatrixCursor cursor = new MatrixCursor(new String[] { BaseColumns._ID });
for (long i = 1; i <= size; i++) {
cursor.addRow(new Object[] { i });
}
return cursor;
}
}
private static class FixedSizeLocationIterator implements LocationIterator {
private final long startId;
private final Location[] locs;
private final Set<Integer> splitIndexSet = new HashSet<Integer>();
private int currentIdx = -1;
public FixedSizeLocationIterator(long startId, int size) {
this(startId, size, null);
}
public FixedSizeLocationIterator(long startId, int size, int... splitIndices) {
this.startId = startId;
this.locs = new Location[size];
for (int i = 0; i < size; i++) {
Location loc = new Location("gps");
loc.setLatitude(-15.0 + i / 1000.0);
loc.setLongitude(37 + i / 1000.0);
loc.setAltitude(i);
locs[i] = loc;
}
if (splitIndices != null) {
for (int splitIdx : splitIndices) {
splitIndexSet.add(splitIdx);
Location splitLoc = locs[splitIdx];
splitLoc.setLatitude(100.0);
splitLoc.setLongitude(200.0);
}
}
}
public void expectLocationsDelivered(TrackDataListener listener) {
for (int i = 0; i < locs.length; i++) {
if (splitIndexSet.contains(i)) {
listener.onSegmentSplit();
} else {
listener.onNewTrackPoint(locs[i]);
}
}
}
public void expectSampledLocationsDelivered(
TrackDataListener listener, int sampleFrequency, boolean includeSampledOut) {
for (int i = 0; i < locs.length; i++) {
if (splitIndexSet.contains(i)) {
listener.onSegmentSplit();
} else if (i % sampleFrequency == 0) {
listener.onNewTrackPoint(locs[i]);
} else if (includeSampledOut) {
listener.onSampledOutTrackPoint(locs[i]);
}
}
}
@Override
public boolean hasNext() {
return currentIdx < (locs.length - 1);
}
@Override
public Location next() {
currentIdx++;
return locs[currentIdx];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public long getLocationId() {
return startId + currentIdx;
}
@Override
public void close() {
// Do nothing
}
}
public void testWaypointListen() {
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
prefs.edit().putLong("recordingTrack", TRACK_ID)
.putLong("selectedTrack", TRACK_ID).apply();
Waypoint wpt1 = new Waypoint(),
wpt2 = new Waypoint(),
wpt3 = new Waypoint(),
wpt4 = new Waypoint();
Location loc = new Location("gps");
loc.setLatitude(10.0);
loc.setLongitude(8.0);
wpt1.setLocation(loc);
wpt2.setLocation(loc);
wpt3.setLocation(loc);
wpt4.setLocation(loc);
expect(providerUtils.getWaypointsCursor(
eq(TRACK_ID), leq(0L), eq(Constants.MAX_DISPLAYED_WAYPOINTS_POINTS)))
.andStubAnswer(new FixedSizeCursorAnswer(2));
expect(providerUtils.createWaypoint(isA(Cursor.class)))
.andReturn(wpt1)
.andReturn(wpt2)
.andReturn(wpt1)
.andReturn(wpt2);
expectStart();
dataSources.registerContentObserver(
eq(WaypointsColumns.CONTENT_URI), eq(false), capture(observerCapture));
// Expect the initial loading.
// Both listeners (registered before and after start) should get the same data.
listener1.clearWaypoints();
listener1.onNewWaypoint(wpt1);
listener1.onNewWaypoint(wpt2);
listener1.onNewWaypointsDone();
listener2.clearWaypoints();
listener2.onNewWaypoint(wpt1);
listener2.onNewWaypoint(wpt2);
listener2.onNewWaypointsDone();
replay();
hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.WAYPOINT_UPDATES));
hub.start();
hub.registerTrackDataListener(listener2, EnumSet.of(ListenerDataType.WAYPOINT_UPDATES));
verifyAndReset();
ContentObserver observer = observerCapture.getValue();
expect(providerUtils.getWaypointsCursor(
eq(TRACK_ID), leq(0L), eq(Constants.MAX_DISPLAYED_WAYPOINTS_POINTS)))
.andStubAnswer(new FixedSizeCursorAnswer(3));
expect(providerUtils.createWaypoint(isA(Cursor.class)))
.andReturn(wpt1)
.andReturn(wpt2)
.andReturn(wpt3);
// Now expect an update.
listener1.clearWaypoints();
listener2.clearWaypoints();
listener1.onNewWaypoint(wpt1);
listener2.onNewWaypoint(wpt1);
listener1.onNewWaypoint(wpt2);
listener2.onNewWaypoint(wpt2);
listener1.onNewWaypoint(wpt3);
listener2.onNewWaypoint(wpt3);
listener1.onNewWaypointsDone();
listener2.onNewWaypointsDone();
replay();
observer.onChange(false);
verifyAndReset();
// Unregister one, get another update.
expect(providerUtils.getWaypointsCursor(
eq(TRACK_ID), leq(0L), eq(Constants.MAX_DISPLAYED_WAYPOINTS_POINTS)))
.andStubAnswer(new FixedSizeCursorAnswer(4));
expect(providerUtils.createWaypoint(isA(Cursor.class)))
.andReturn(wpt1)
.andReturn(wpt2)
.andReturn(wpt3)
.andReturn(wpt4);
// Now expect an update.
listener2.clearWaypoints();
listener2.onNewWaypoint(wpt1);
listener2.onNewWaypoint(wpt2);
listener2.onNewWaypoint(wpt3);
listener2.onNewWaypoint(wpt4);
listener2.onNewWaypointsDone();
replay();
hub.unregisterTrackDataListener(listener1);
observer.onChange(false);
verifyAndReset();
// Unregister the other, expect internal unregistration
dataSources.unregisterContentObserver(observer);
replay();
hub.unregisterTrackDataListener(listener2);
observer.onChange(false);
verifyAndReset();
}
public void testPointsListen() {
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
prefs.edit().putLong("recordingTrack", TRACK_ID)
.putLong("selectedTrack", TRACK_ID).apply();
expectStart();
dataSources.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture));
FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 10, 5);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(10L);
listener1.clearTrackPoints();
locationIterator.expectLocationsDelivered(listener1);
listener1.onNewTrackPointsDone();
replay();
hub.start();
hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.POINT_UPDATES));
verifyAndReset();
// Register a second listener - it will get the same points as the previous one
locationIterator = new FixedSizeLocationIterator(1, 10, 5);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(10L);
listener2.clearTrackPoints();
locationIterator.expectLocationsDelivered(listener2);
listener2.onNewTrackPointsDone();
replay();
hub.start();
hub.registerTrackDataListener(listener2, EnumSet.of(ListenerDataType.POINT_UPDATES));
verifyAndReset();
// Deliver more points - should go to both listeners, without clearing.
ContentObserver observer = observerCapture.getValue();
locationIterator = new FixedSizeLocationIterator(11, 10, 1);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID), eq(11L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(20L);
locationIterator.expectLocationsDelivered(listener1);
locationIterator.expectLocationsDelivered(listener2);
listener1.onNewTrackPointsDone();
listener2.onNewTrackPointsDone();
replay();
observer.onChange(false);
verifyAndReset();
// Unregister listener1, switch tracks to ensure data is cleared/reloaded.
locationIterator = new FixedSizeLocationIterator(101, 10);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID + 1), eq(0L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID + 1)).andReturn(110L);
listener2.clearTrackPoints();
locationIterator.expectLocationsDelivered(listener2);
listener2.onNewTrackPointsDone();
replay();
hub.unregisterTrackDataListener(listener1);
hub.loadTrack(TRACK_ID + 1);
verifyAndReset();
}
public void testPointsListen_beforeStart() {
}
public void testPointsListen_reRegister() {
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
prefs.edit().putLong("recordingTrack", TRACK_ID)
.putLong("selectedTrack", TRACK_ID).apply();
expectStart();
dataSources.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture));
FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 10, 5);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(10L);
listener1.clearTrackPoints();
locationIterator.expectLocationsDelivered(listener1);
listener1.onNewTrackPointsDone();
replay();
hub.start();
hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.POINT_UPDATES));
verifyAndReset();
// Unregister
ContentObserver observer = observerCapture.getValue();
dataSources.unregisterContentObserver(observer);
replay();
hub.unregisterTrackDataListener(listener1);
verifyAndReset();
// Register again, except only points since unregistered.
dataSources.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture));
locationIterator = new FixedSizeLocationIterator(11, 10);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID), eq(11L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(20L);
locationIterator.expectLocationsDelivered(listener1);
listener1.onNewTrackPointsDone();
replay();
hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.POINT_UPDATES));
verifyAndReset();
// Deliver more points - should still be incremental.
locationIterator = new FixedSizeLocationIterator(21, 10, 1);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID), eq(21L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(30L);
locationIterator.expectLocationsDelivered(listener1);
listener1.onNewTrackPointsDone();
replay();
observer.onChange(false);
verifyAndReset();
}
public void testPointsListen_reRegisterTrackChanged() {
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
prefs.edit().putLong("recordingTrack", TRACK_ID)
.putLong("selectedTrack", TRACK_ID).apply();
expectStart();
dataSources.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture));
FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 10, 5);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(10L);
listener1.clearTrackPoints();
locationIterator.expectLocationsDelivered(listener1);
listener1.onNewTrackPointsDone();
replay();
hub.start();
hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.POINT_UPDATES));
verifyAndReset();
// Unregister
ContentObserver observer = observerCapture.getValue();
dataSources.unregisterContentObserver(observer);
replay();
hub.unregisterTrackDataListener(listener1);
verifyAndReset();
// Register again after track changed, expect all points.
dataSources.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture));
locationIterator = new FixedSizeLocationIterator(1, 10);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID + 1), eq(0L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID + 1)).andReturn(10L);
listener1.clearTrackPoints();
locationIterator.expectLocationsDelivered(listener1);
listener1.onNewTrackPointsDone();
replay();
hub.loadTrack(TRACK_ID + 1);
hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.POINT_UPDATES));
verifyAndReset();
}
public void testPointsListen_largeTrackSampling() {
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
prefs.edit().putLong("recordingTrack", TRACK_ID)
.putLong("selectedTrack", TRACK_ID).apply();
expectStart();
dataSources.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture));
FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 200, 4, 25, 71, 120);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(200L);
listener1.clearTrackPoints();
listener2.clearTrackPoints();
locationIterator.expectSampledLocationsDelivered(listener1, 4, false);
locationIterator.expectSampledLocationsDelivered(listener2, 4, true);
listener1.onNewTrackPointsDone();
listener2.onNewTrackPointsDone();
replay();
hub.registerTrackDataListener(listener1,
EnumSet.of(ListenerDataType.POINT_UPDATES));
hub.registerTrackDataListener(listener2,
EnumSet.of(ListenerDataType.POINT_UPDATES, ListenerDataType.SAMPLED_OUT_POINT_UPDATES));
hub.start();
verifyAndReset();
}
public void testPointsListen_resampling() {
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
prefs.edit().putLong("recordingTrack", TRACK_ID)
.putLong("selectedTrack", TRACK_ID).apply();
expectStart();
dataSources.registerContentObserver(
eq(TrackPointsColumns.CONTENT_URI), eq(false), capture(observerCapture));
// Deliver 30 points (no sampling happens)
FixedSizeLocationIterator locationIterator = new FixedSizeLocationIterator(1, 30, 5);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(30L);
listener1.clearTrackPoints();
locationIterator.expectLocationsDelivered(listener1);
listener1.onNewTrackPointsDone();
replay();
hub.start();
hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.POINT_UPDATES));
verifyAndReset();
// Now deliver 30 more (incrementally sampled)
ContentObserver observer = observerCapture.getValue();
locationIterator = new FixedSizeLocationIterator(31, 30);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID), eq(31L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(60L);
locationIterator.expectSampledLocationsDelivered(listener1, 2, false);
listener1.onNewTrackPointsDone();
replay();
observer.onChange(false);
verifyAndReset();
// Now another 30 (triggers resampling)
locationIterator = new FixedSizeLocationIterator(1, 90);
expect(providerUtils.getLocationIterator(
eq(TRACK_ID), eq(0L), eq(false), isA(LocationFactory.class)))
.andReturn(locationIterator);
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(90L);
listener1.clearTrackPoints();
locationIterator.expectSampledLocationsDelivered(listener1, 2, false);
listener1.onNewTrackPointsDone();
replay();
observer.onChange(false);
verifyAndReset();
}
public void testLocationListen() {
// TODO
}
public void testCompassListen() throws Exception {
AndroidMock.resetToDefault(listener1);
Sensor compass = newSensor();
expect(dataSources.getSensor(Sensor.TYPE_ORIENTATION)).andReturn(compass);
Capture<SensorEventListener> listenerCapture = new Capture<SensorEventListener>();
dataSources.registerSensorListener(capture(listenerCapture), same(compass), anyInt());
Capture<LocationListener> locationListenerCapture = new Capture<LocationListener>();
dataSources.requestLocationUpdates(capture(locationListenerCapture));
SensorEvent event = newSensorEvent();
event.sensor = compass;
// First, get a dummy heading update.
listener1.onCurrentHeadingChanged(0.0);
// Then, get a heading update without a known location (thus can't calculate declination).
listener1.onCurrentHeadingChanged(42.0f);
// Also expect location updates which are not relevant to us.
listener1.onProviderStateChange(isA(ProviderState.class));
AndroidMock.expectLastCall().anyTimes();
replay();
hub.registerTrackDataListener(listener1,
EnumSet.of(ListenerDataType.COMPASS_UPDATES, ListenerDataType.LOCATION_UPDATES));
hub.start();
SensorEventListener sensorListener = listenerCapture.getValue();
LocationListener locationListener = locationListenerCapture.getValue();
event.values[0] = 42.0f;
sensorListener.onSensorChanged(event);
verifyAndReset();
// Expect the heading update to include declination.
listener1.onCurrentHeadingChanged(52.0);
// Also expect location updates which are not relevant to us.
listener1.onProviderStateChange(isA(ProviderState.class));
AndroidMock.expectLastCall().anyTimes();
listener1.onCurrentLocationChanged(isA(Location.class));
AndroidMock.expectLastCall().anyTimes();
replay();
// Now try injecting a location update, triggering a declination update.
Location location = new Location("gps");
location.setLatitude(10.0);
location.setLongitude(20.0);
location.setAltitude(30.0);
declination = 10.0f;
locationListener.onLocationChanged(location);
sensorListener.onSensorChanged(event);
verifyAndReset();
listener1.onCurrentHeadingChanged(52.0);
replay();
// Now try changing the known declination - it should still return the old declination, since
// updates only happen sparsely.
declination = 20.0f;
sensorListener.onSensorChanged(event);
verifyAndReset();
}
private Sensor newSensor() throws Exception {
Constructor<Sensor> constructor = Sensor.class.getDeclaredConstructor();
constructor.setAccessible(true);
return constructor.newInstance();
}
private SensorEvent newSensorEvent() throws Exception {
Constructor<SensorEvent> constructor = SensorEvent.class.getDeclaredConstructor(int.class);
constructor.setAccessible(true);
return constructor.newInstance(3);
}
public void testDisplayPreferencesListen() throws Exception {
String metricUnitsKey = context.getString(R.string.metric_units_key);
String speedKey = context.getString(R.string.report_speed_key);
prefs.edit()
.putBoolean(metricUnitsKey, true)
.putBoolean(speedKey, true)
.apply();
Capture<OnSharedPreferenceChangeListener> listenerCapture =
new Capture<OnSharedPreferenceChangeListener>();
dataSources.registerOnSharedPreferenceChangeListener(capture(listenerCapture));
expect(listener1.onUnitsChanged(true)).andReturn(false);
expect(listener2.onUnitsChanged(true)).andReturn(false);
expect(listener1.onReportSpeedChanged(true)).andReturn(false);
expect(listener2.onReportSpeedChanged(true)).andReturn(false);
replay();
hub.registerTrackDataListener(listener1, EnumSet.of(ListenerDataType.DISPLAY_PREFERENCES));
hub.start();
hub.registerTrackDataListener(listener2, EnumSet.of(ListenerDataType.DISPLAY_PREFERENCES));
verifyAndReset();
expect(listener1.onReportSpeedChanged(false)).andReturn(false);
expect(listener2.onReportSpeedChanged(false)).andReturn(false);
replay();
prefs.edit()
.putBoolean(speedKey, false)
.apply();
OnSharedPreferenceChangeListener listener = listenerCapture.getValue();
listener.onSharedPreferenceChanged(prefs, speedKey);
AndroidMock.verify(dataSources, providerUtils, listener1, listener2);
AndroidMock.reset(dataSources, providerUtils, listener1, listener2);
expect(listener1.onUnitsChanged(false)).andReturn(false);
expect(listener2.onUnitsChanged(false)).andReturn(false);
replay();
prefs.edit()
.putBoolean(metricUnitsKey, false)
.apply();
listener.onSharedPreferenceChanged(prefs, metricUnitsKey);
verifyAndReset();
}
private void expectStart() {
dataSources.registerOnSharedPreferenceChangeListener(capture(preferenceListenerCapture));
}
private void replay() {
AndroidMock.replay(dataSources, providerUtils, listener1, listener2);
}
private void verifyAndReset() {
AndroidMock.verify(listener1, listener2, dataSources, providerUtils);
AndroidMock.reset(listener1, listener2, dataSources, providerUtils);
}
}
@@ -0,0 +1,55 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.content.WaypointCreationRequest.WaypointType;
import android.os.Parcel;
import android.test.AndroidTestCase;
/**
* Tests for the WaypointCreationRequest class.
* {@link WaypointCreationRequest}
*
* @author Sandor Dornbush
*/
public class WaypointCreationRequestTest extends AndroidTestCase {
public void testTypeParceling() {
WaypointCreationRequest original = WaypointCreationRequest.DEFAULT_MARKER;
Parcel p = Parcel.obtain();
original.writeToParcel(p, 0);
p.setDataPosition(0);
WaypointCreationRequest copy = WaypointCreationRequest.CREATOR.createFromParcel(p);
assertEquals(original.getType(), copy.getType());
assertNull(copy.getName());
assertNull(copy.getDescription());
assertNull(copy.getIconUrl());
}
public void testAllAttributesParceling() {
WaypointCreationRequest original =
new WaypointCreationRequest(WaypointType.MARKER, "name", "description", "img.png");
Parcel p = Parcel.obtain();
original.writeToParcel(p, 0);
p.setDataPosition(0);
WaypointCreationRequest copy = WaypointCreationRequest.CREATOR.createFromParcel(p);
assertEquals(original.getType(), copy.getType());
assertEquals("name", copy.getName());
assertEquals("description", copy.getDescription());
assertEquals("img.png", copy.getIconUrl());
}
}
@@ -0,0 +1,267 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.content.ContentTypeIds;
import android.database.MatrixCursor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import junit.framework.TestCase;
/**
* Tests for {@link DatabaseDumper}.
*
* @author Rodrigo Damazio
*/
public class DatabaseDumperTest extends TestCase {
/**
* This class is the same as {@link MatrixCursor}, except this class
* implements {@link #getBlob} ({@link MatrixCursor} leaves it
* unimplemented).
*/
private class BlobAwareMatrixCursor extends MatrixCursor {
public BlobAwareMatrixCursor(String[] columnNames) {
super(columnNames);
}
@Override public byte[] getBlob(int columnIndex) {
return getString(columnIndex).getBytes();
}
}
private static final String[] COLUMN_NAMES = {
"intCol", "longCol", "floatCol", "doubleCol", "stringCol", "boolCol", "blobCol"
};
private static final byte[] COLUMN_TYPES = {
ContentTypeIds.INT_TYPE_ID, ContentTypeIds.LONG_TYPE_ID,
ContentTypeIds.FLOAT_TYPE_ID, ContentTypeIds.DOUBLE_TYPE_ID,
ContentTypeIds.STRING_TYPE_ID, ContentTypeIds.BOOLEAN_TYPE_ID,
ContentTypeIds.BLOB_TYPE_ID
};
private static final String[][] FAKE_DATA = {
{ "42", "123456789", "3.1415", "2.72", "lolcat", "1", "blob" },
{ null, "123456789", "3.1415", "2.72", "lolcat", "1", "blob" },
{ "42", null, "3.1415", "2.72", "lolcat", "1", "blob" },
{ "42", "123456789", null, "2.72", "lolcat", "1", "blob" },
{ "42", "123456789", "3.1415", null, "lolcat", "1", "blob" },
{ "42", "123456789", "3.1415", "2.72", null, "1", "blob" },
{ "42", "123456789", "3.1415", "2.72", "lolcat", null, "blob" },
{ "42", "123456789", "3.1415", "2.72", "lolcat", "1", null },
};
private static final long[] EXPECTED_FIELD_SETS = {
0x7F, 0x7E, 0x7D, 0x7B, 0x77, 0x6F, 0x5F, 0x3F
};
private BlobAwareMatrixCursor cursor;
@Override
protected void setUp() throws Exception {
super.setUp();
// Add fake data to the cursor
cursor = new BlobAwareMatrixCursor(COLUMN_NAMES);
for (String[] row : FAKE_DATA) {
cursor.addRow(row);
}
}
public void testWriteAllRows_noNulls() throws Exception {
testWriteAllRows(false);
}
public void testWriteAllRows_withNulls() throws Exception {
testWriteAllRows(true);
}
private void testWriteAllRows(boolean hasNullFields) throws Exception {
// Dump it
DatabaseDumper dumper = new DatabaseDumper(COLUMN_NAMES, COLUMN_TYPES, hasNullFields);
ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);
DataOutputStream writer = new DataOutputStream(outStream );
dumper.writeAllRows(cursor, writer);
// Read the results
byte[] result = outStream.toByteArray();
ByteArrayInputStream inputStream = new ByteArrayInputStream(result);
DataInputStream reader = new DataInputStream(inputStream);
// Verify the header
assertHeader(reader);
// Verify the number of rows
assertEquals(FAKE_DATA.length, reader.readInt());
// Row 0 -- everything populated
assertEquals(EXPECTED_FIELD_SETS[0], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 1 -- no int
assertEquals(EXPECTED_FIELD_SETS[1], reader.readLong());
if (hasNullFields) reader.readInt();
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 2 -- no long
assertEquals(EXPECTED_FIELD_SETS[2], reader.readLong());
assertEquals(42, reader.readInt());
if (hasNullFields) reader.readLong();
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 3 -- no float
assertEquals(EXPECTED_FIELD_SETS[3], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
if (hasNullFields) reader.readFloat();
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 4 -- no double
assertEquals(EXPECTED_FIELD_SETS[4], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
if (hasNullFields) reader.readDouble();
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 5 -- no string
assertEquals(EXPECTED_FIELD_SETS[5], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
if (hasNullFields) reader.readUTF();
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 6 -- no boolean
assertEquals(EXPECTED_FIELD_SETS[6], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
if (hasNullFields) reader.readBoolean();
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 7 -- no blob
assertEquals(EXPECTED_FIELD_SETS[7], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
if (hasNullFields) {
int length = reader.readInt();
readBlob(reader, length);
}
}
public void testFewerRows() throws Exception {
// Dump only the first two rows
DatabaseDumper dumper = new DatabaseDumper(COLUMN_NAMES, COLUMN_TYPES, false);
ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);
DataOutputStream writer = new DataOutputStream(outStream);
dumper.writeHeaders(cursor, 2, writer);
cursor.moveToFirst();
dumper.writeOneRow(cursor, writer);
cursor.moveToNext();
dumper.writeOneRow(cursor, writer);
// Read the results
byte[] result = outStream.toByteArray();
ByteArrayInputStream inputStream = new ByteArrayInputStream(result);
DataInputStream reader = new DataInputStream(inputStream);
// Verify the header
assertHeader(reader);
// Verify the number of rows
assertEquals(2, reader.readInt());
// Row 0
assertEquals(EXPECTED_FIELD_SETS[0], reader.readLong());
assertEquals(42, reader.readInt());
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
// Row 1
assertEquals(EXPECTED_FIELD_SETS[1], reader.readLong());
// Null field not read
assertEquals(123456789L, reader.readLong());
assertEquals(3.1415f, reader.readFloat());
assertEquals(2.72, reader.readDouble());
assertEquals("lolcat", reader.readUTF());
assertTrue(reader.readBoolean());
assertEquals(4, reader.readInt());
assertEquals("blob", readBlob(reader, 4));
}
private void assertHeader(DataInputStream reader) throws IOException {
assertEquals(COLUMN_NAMES.length, reader.readInt());
for (int i = 0; i < COLUMN_NAMES.length; i++) {
assertEquals(COLUMN_NAMES[i], reader.readUTF());
assertEquals(COLUMN_TYPES[i], reader.readByte());
}
}
private String readBlob(InputStream reader, int length) throws Exception {
if (length == 0) {
return "";
}
byte[] blob = new byte[length];
assertEquals(length, reader.read(blob));
return new String(blob);
}
}
@@ -0,0 +1,293 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.content.ContentTypeIds;
import android.content.ContentValues;
import android.net.Uri;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import junit.framework.TestCase;
/**
* Tests for {@link DatabaseImporter}.
*
* @author Rodrigo Damazio
*/
public class DatabaseImporterTest extends TestCase {
private static final Uri DESTINATION_URI = Uri.parse("http://www.google.com/");
private static final int TEST_BULK_SIZE = 10;
private ArrayList<ContentValues> insertedValues;
private class TestableDatabaseImporter extends DatabaseImporter {
public TestableDatabaseImporter(boolean readNullFields) {
super(DESTINATION_URI, null, readNullFields, TEST_BULK_SIZE);
}
@Override
protected void doBulkInsert(ContentValues[] values) {
insertedValues.ensureCapacity(insertedValues.size() + values.length);
// We need to make a copy of the values since the objects are re-used
for (ContentValues contentValues : values) {
insertedValues.add(new ContentValues(contentValues));
}
}
}
@Override
protected void setUp() throws Exception {
super.setUp();
insertedValues = new ArrayList<ContentValues>();
}
public void testImportAllRows() throws Exception {
testImportAllRows(false);
}
public void testImportAllRows_readNullFields() throws Exception {
testImportAllRows(true);
}
private void testImportAllRows(boolean readNullFields) throws Exception {
// Create a fake data stream to be read
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
DataOutputStream writer = new DataOutputStream(outputStream);
writeFullHeader(writer);
// Add the number of rows
writer.writeInt(2);
// Add a row with all fields present
writer.writeLong(0x7F);
writer.writeInt(42);
writer.writeBoolean(true);
writer.writeUTF("lolcat");
writer.writeFloat(3.1415f);
writer.writeDouble(2.72);
writer.writeLong(123456789L);
writer.writeInt(4);
writer.writeBytes("blob");
// Add a row with some missing fields
writer.writeLong(0x15);
writer.writeInt(42);
if (readNullFields) writer.writeBoolean(false);
writer.writeUTF("lolcat");
if (readNullFields) writer.writeFloat(0.0f);
writer.writeDouble(2.72);
if (readNullFields) writer.writeLong(0L);
if (readNullFields) writer.writeInt(0); // empty blob
writer.flush();
// Do the importing
DatabaseImporter importer = new TestableDatabaseImporter(readNullFields);
byte[] dataBytes = outputStream.toByteArray();
importer.importAllRows(new DataInputStream(new ByteArrayInputStream(dataBytes)));
assertEquals(2, insertedValues.size());
// Verify the first row
ContentValues value = insertedValues.get(0);
assertEquals(value.toString(), 7, value.size());
assertValue(42, "col1", value);
assertValue(true, "col2", value);
assertValue("lolcat", "col3", value);
assertValue(3.1415f, "col4", value);
assertValue(2.72, "col5", value);
assertValue(123456789L, "col6", value);
assertBlobValue("blob", "col7", value);
// Verify the second row
value = insertedValues.get(1);
assertEquals(value.toString(), 3, value.size());
assertValue(42, "col1", value);
assertValue("lolcat", "col3", value);
assertValue(2.72, "col5", value);
}
public void testImportAllRows_noRows() throws Exception {
// Create a fake data stream to be read
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
DataOutputStream writer = new DataOutputStream(outputStream);
writeFullHeader(writer);
// Add the number of rows
writer.writeInt(0);
writer.flush();
// Do the importing
DatabaseImporter importer = new TestableDatabaseImporter(false);
byte[] dataBytes = outputStream.toByteArray();
importer.importAllRows(new DataInputStream(new ByteArrayInputStream(dataBytes)));
assertTrue(insertedValues.isEmpty());
}
public void testImportAllRows_emptyRows() throws Exception {
testImportAllRowsWithEmptyRows(false);
}
public void testImportAllRows_emptyRowsWithNulls() throws Exception {
testImportAllRowsWithEmptyRows(true);
}
private void testImportAllRowsWithEmptyRows(boolean readNullFields) throws Exception {
// Create a fake data stream to be read
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
DataOutputStream writer = new DataOutputStream(outputStream);
writeFullHeader(writer);
// Add the number of rows
writer.writeInt(3);
// Add 2 rows with no fields
for (int i = 0; i < 2; i++) {
writer.writeLong(0);
if (readNullFields) {
writer.writeInt(0);
writer.writeBoolean(false);
writer.writeUTF("");
writer.writeFloat(0.0f);
writer.writeDouble(0.0);
writer.writeLong(0L);
writer.writeInt(0); // empty blob
}
}
// Add a row with some missing fields
writer.writeLong(0x15);
writer.writeInt(42);
if (readNullFields) writer.writeBoolean(false);
writer.writeUTF("lolcat");
if (readNullFields) writer.writeFloat(0.0f);
writer.writeDouble(2.72);
if (readNullFields) writer.writeLong(0L);
if (readNullFields) writer.writeInt(0); // empty blob
writer.flush();
// Do the importing
DatabaseImporter importer = new TestableDatabaseImporter(readNullFields);
byte[] dataBytes = outputStream.toByteArray();
importer.importAllRows(new DataInputStream(new ByteArrayInputStream(dataBytes)));
assertEquals(insertedValues.toString(), 3, insertedValues.size());
ContentValues value = insertedValues.get(0);
assertEquals(value.toString(), 0, value.size());
value = insertedValues.get(1);
assertEquals(value.toString(), 0, value.size());
// Verify the third row (only one with values)
value = insertedValues.get(2);
assertEquals(value.toString(), 3, value.size());
assertFalse(value.containsKey("col2"));
assertFalse(value.containsKey("col4"));
assertFalse(value.containsKey("col6"));
assertValue(42, "col1", value);
assertValue("lolcat", "col3", value);
assertValue(2.72, "col5", value);
}
public void testImportAllRows_bulks() throws Exception {
// Create a fake data stream to be read
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
DataOutputStream writer = new DataOutputStream(outputStream);
// Add the header
writer.writeInt(2);
writer.writeUTF("col1");
writer.writeByte(ContentTypeIds.INT_TYPE_ID);
writer.writeUTF("col2");
writer.writeByte(ContentTypeIds.STRING_TYPE_ID);
// Add lots of rows (so the insertions are split in multiple bulks)
int numRows = TEST_BULK_SIZE * 5 / 2;
writer.writeInt(numRows);
for (int i = 0; i < numRows; i++) {
writer.writeLong(3);
writer.writeInt(i);
writer.writeUTF(Integer.toString(i * 2));
}
writer.flush();
// Do the importing
DatabaseImporter importer = new TestableDatabaseImporter(false);
byte[] dataBytes = outputStream.toByteArray();
importer.importAllRows(new DataInputStream(new ByteArrayInputStream(dataBytes)));
// Verify the rows
assertEquals(numRows, insertedValues.size());
for (int i = 0; i < numRows; i++) {
ContentValues value = insertedValues.get(i);
assertEquals(value.toString(), 2, value.size());
assertValue(i, "col1", value);
assertValue(Integer.toString(i * 2), "col2", value);
}
}
private void writeFullHeader(DataOutputStream writer) throws IOException {
// Add the header
writer.writeInt(7);
writer.writeUTF("col1");
writer.writeByte(ContentTypeIds.INT_TYPE_ID);
writer.writeUTF("col2");
writer.writeByte(ContentTypeIds.BOOLEAN_TYPE_ID);
writer.writeUTF("col3");
writer.writeByte(ContentTypeIds.STRING_TYPE_ID);
writer.writeUTF("col4");
writer.writeByte(ContentTypeIds.FLOAT_TYPE_ID);
writer.writeUTF("col5");
writer.writeByte(ContentTypeIds.DOUBLE_TYPE_ID);
writer.writeUTF("col6");
writer.writeByte(ContentTypeIds.LONG_TYPE_ID);
writer.writeUTF("col7");
writer.writeByte(ContentTypeIds.BLOB_TYPE_ID);
}
private <T> void assertValue(T expectedValue, String name, ContentValues values) {
@SuppressWarnings("unchecked")
T value = (T) values.get(name);
assertNotNull(value);
assertEquals(expectedValue, value);
}
private void assertBlobValue(String expectedValue, String name, ContentValues values ){
byte[] blob = values.getAsByteArray(name);
assertEquals(expectedValue, new String(blob));
}
}
@@ -0,0 +1,211 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.backup;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import junit.framework.TestCase;
/**
* Tests for {@link PreferenceBackupHelper}.
*
* @author Rodrigo Damazio
*/
public class PreferenceBackupHelperTest extends TestCase {
private Map<String, ?> preferenceValues;
private SharedPreferences preferences;
private PreferenceBackupHelper preferenceBackupHelper;
/**
* Mock shared preferences editor which does not persist state.
*/
private class MockPreferenceEditor implements SharedPreferences.Editor {
private Map<String, Object> newPreferences = new HashMap<String, Object>(preferenceValues);
@Override
public Editor clear() {
newPreferences.clear();
return this;
}
@Override
public boolean commit() {
apply();
return true;
}
@Override
public void apply() {
preferenceValues = newPreferences;
}
@Override
public Editor putBoolean(String key, boolean value) {
return put(key, value);
}
@Override
public Editor putFloat(String key, float value) {
return put(key, value);
}
@Override
public Editor putInt(String key, int value) {
return put(key, value);
}
@Override
public Editor putLong(String key, long value) {
return put(key, value);
}
@Override
public Editor putString(String key, String value) {
return put(key, value);
}
public Editor putStringSet(String key, Set<String> value) {
return put(key, value);
}
private <T> Editor put(String key, T value) {
newPreferences.put(key, value);
return this;
}
@Override
public Editor remove(String key) {
newPreferences.remove(key);
return this;
}
}
/**
* Mock shared preferences which does not persist state.
*/
private class MockPreferences implements SharedPreferences {
@Override
public boolean contains(String key) {
return preferenceValues.containsKey(key);
}
@Override
public Editor edit() {
return new MockPreferenceEditor();
}
@Override
public Map<String, ?> getAll() {
return preferenceValues;
}
@Override
public boolean getBoolean(String key, boolean defValue) {
return get(key, defValue);
}
@Override
public float getFloat(String key, float defValue) {
return get(key, defValue);
}
@Override
public int getInt(String key, int defValue) {
return get(key, defValue);
}
@Override
public long getLong(String key, long defValue) {
return get(key, defValue);
}
@Override
public String getString(String key, String defValue) {
return get(key, defValue);
}
public Set<String> getStringSet(String key, Set<String> defValue) {
return get(key, defValue);
}
@Override
public void registerOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void unregisterOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("unchecked")
private <T> T get(String key, T defValue) {
Object value = preferenceValues.get(key);
if (value == null) return defValue;
return (T) value;
}
}
@Override
protected void setUp() throws Exception {
super.setUp();
preferenceValues = new HashMap<String, Object>();
preferences = new MockPreferences();
preferenceBackupHelper = new PreferenceBackupHelper();
}
public void testExportImportPreferences() throws Exception {
// Populate with some initial values
Editor editor = preferences.edit();
editor.clear();
editor.putBoolean("bool1", true);
editor.putBoolean("bool2", false);
editor.putFloat("flt1", 3.14f);
editor.putInt("int1", 42);
editor.putLong("long1", 123456789L);
editor.putString("str1", "lolcat");
editor.apply();
// Export it
byte[] exported = preferenceBackupHelper.exportPreferences(preferences);
// Mess with the previous values
editor = preferences.edit();
editor.clear();
editor.putString("str2", "Shouldn't be there after restore");
editor.putBoolean("bool2", true);
editor.apply();
// Import it back
preferenceBackupHelper.importPreferences(exported, preferences);
assertFalse(preferences.contains("str2"));
assertTrue(preferences.getBoolean("bool1", false));
assertFalse(preferences.getBoolean("bool2", true));
assertEquals(3.14f, preferences.getFloat("flt1", 0.0f));
assertEquals(42, preferences.getInt("int1", 0));
assertEquals(123456789L, preferences.getLong("long1", 0));
assertEquals("lolcat", preferences.getString("str1", ""));
}
}
@@ -0,0 +1,246 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.docs;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.gdata.docs.SpreadsheetsClient.WorksheetEntry;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.wireless.gdata.data.Entry;
import android.test.AndroidTestCase;
/**
* Tests {@link SendDocsUtils}.
*
* @author Jimmy Shih
*/
public class SendDocsUtilsTest extends AndroidTestCase {
private static final long TIME = 1288721514000L;
/**
* Tests {@link SendDocsUtils#getEntryId(Entry)} with a valid id.
*/
public void testGetEntryId_valid() {
Entry entry = new Entry();
entry.setId("https://docs.google.com/feeds/documents/private/full/spreadsheet%3A123");
assertEquals("123", SendDocsUtils.getEntryId(entry));
}
/**
* Tests {@link SendDocsUtils#getEntryId(Entry)} with an invalid id.
*/
public void testGetEntryId_invalid() {
Entry entry = new Entry();
entry.setId("123");
assertEquals(null, SendDocsUtils.getEntryId(entry));
}
/**
* Tests {@link SendDocsUtils#getNewSpreadsheetId(String)} with a valid id.
*/
public void testGetNewSpreadsheetId_valid_id() {
assertEquals("123", SendDocsUtils.getNewSpreadsheetId(
"<id>https://docs.google.com/feeds/documents/private/full/spreadsheet%3A123</id>"));
}
/**
* Tests {@link SendDocsUtils#getNewSpreadsheetId(String)} without an open
* tag, <id>.
*/
public void testGetNewSpreadsheetId_no_open_tag() {
assertEquals(null, SendDocsUtils.getNewSpreadsheetId(
"https://docs.google.com/feeds/documents/private/full/spreadsheet%3A123</id>"));
}
/**
* Tests {@link SendDocsUtils#getNewSpreadsheetId(String)} without an end tag,
* </id>.
*/
public void testGetNewSpreadsheetId_no_end_tag() {
assertEquals(null, SendDocsUtils.getNewSpreadsheetId(
"<id>https://docs.google.com/feeds/documents/private/full/spreadsheet%3A123"));
}
/**
* Tests {@link SendDocsUtils#getNewSpreadsheetId(String)} without the url
* prefix,
* https://docs.google.com/feeds/documents/private/full/spreadsheet%3A.
*/
public void testGetNewSpreadsheetId_no_prefix() {
assertEquals(null, SendDocsUtils.getNewSpreadsheetId("<id>123</id>"));
}
/**
* Tests {@link SendDocsUtils#getWorksheetEntryId(WorksheetEntry)} with a
* valid entry.
*/
public void testGetWorksheetEntryId_valid() {
WorksheetEntry entry = new WorksheetEntry();
entry.setId("/123");
assertEquals("123", SendDocsUtils.getWorksheetEntryId(entry));
}
/**
* Tests {@link SendDocsUtils#getWorksheetEntryId(WorksheetEntry)} with a
* invalid entry.
*/
public void testGetWorksheetEntryId_invalid() {
WorksheetEntry entry = new WorksheetEntry();
entry.setId("123");
assertEquals(null, SendDocsUtils.getWorksheetEntryId(entry));
}
/**
* Tests {@link SendDocsUtils#getRowContent(Track, boolean,
* android.content.Context)} with metric units.
*/
public void testGetRowContent_metric() throws Exception {
Track track = getTrack();
String expectedData = "<entry xmlns='http://www.w3.org/2005/Atom' "
+ "xmlns:gsx='http://schemas.google.com/spreadsheets/2006/extended'>"
+ "<gsx:name><![CDATA[trackName]]></gsx:name>"
+ "<gsx:description><![CDATA[trackDescription]]></gsx:description>" + "<gsx:date><![CDATA["
+ StringUtils.formatDateTime(getContext(), TIME) + "]]></gsx:date>"
+ "<gsx:totaltime><![CDATA[0:00:05]]></gsx:totaltime>"
+ "<gsx:movingtime><![CDATA[0:00:04]]></gsx:movingtime>"
+ "<gsx:distance><![CDATA[20.00]]></gsx:distance>"
+ "<gsx:distanceunit><![CDATA[km]]></gsx:distanceunit>"
+ "<gsx:averagespeed><![CDATA[14,400.00]]></gsx:averagespeed>"
+ "<gsx:averagemovingspeed><![CDATA[18,000.00]]>" + "</gsx:averagemovingspeed>"
+ "<gsx:maxspeed><![CDATA[5,400.00]]></gsx:maxspeed>"
+ "<gsx:speedunit><![CDATA[km/h]]></gsx:speedunit>"
+ "<gsx:elevationgain><![CDATA[6,000]]></gsx:elevationgain>"
+ "<gsx:minelevation><![CDATA[-500]]></gsx:minelevation>"
+ "<gsx:maxelevation><![CDATA[550]]></gsx:maxelevation>"
+ "<gsx:elevationunit><![CDATA[m]]></gsx:elevationunit>" + "<gsx:map>"
+ "<![CDATA[https://maps.google.com/maps/ms?msa=0&msid=trackMapId]]>" + "</gsx:map>"
+ "</entry>";
assertEquals(expectedData, SendDocsUtils.getRowContent(track, true, getContext()));
}
/**
* Tests {@link SendDocsUtils#getRowContent(Track, boolean,
* android.content.Context)} with imperial units.
*/
public void testGetRowContent_imperial() throws Exception {
Track track = getTrack();
String expectedData = "<entry xmlns='http://www.w3.org/2005/Atom' "
+ "xmlns:gsx='http://schemas.google.com/spreadsheets/2006/extended'>"
+ "<gsx:name><![CDATA[trackName]]></gsx:name>"
+ "<gsx:description><![CDATA[trackDescription]]></gsx:description>" + "<gsx:date><![CDATA["
+ StringUtils.formatDateTime(getContext(), TIME) + "]]></gsx:date>"
+ "<gsx:totaltime><![CDATA[0:00:05]]></gsx:totaltime>"
+ "<gsx:movingtime><![CDATA[0:00:04]]></gsx:movingtime>"
+ "<gsx:distance><![CDATA[12.43]]></gsx:distance>"
+ "<gsx:distanceunit><![CDATA[mi]]></gsx:distanceunit>"
+ "<gsx:averagespeed><![CDATA[8,947.75]]></gsx:averagespeed>"
+ "<gsx:averagemovingspeed><![CDATA[11,184.68]]>" + "</gsx:averagemovingspeed>"
+ "<gsx:maxspeed><![CDATA[3,355.40]]></gsx:maxspeed>"
+ "<gsx:speedunit><![CDATA[mi/h]]></gsx:speedunit>"
+ "<gsx:elevationgain><![CDATA[19,685]]></gsx:elevationgain>"
+ "<gsx:minelevation><![CDATA[-1,640]]></gsx:minelevation>"
+ "<gsx:maxelevation><![CDATA[1,804]]></gsx:maxelevation>"
+ "<gsx:elevationunit><![CDATA[ft]]></gsx:elevationunit>" + "<gsx:map>"
+ "<![CDATA[https://maps.google.com/maps/ms?msa=0&msid=trackMapId]]>" + "</gsx:map>"
+ "</entry>";
assertEquals(expectedData, SendDocsUtils.getRowContent(track, false, getContext()));
}
/**
* Gets a track for testing {@link SendDocsUtils#getRowContent(Track, boolean,
* android.content.Context)}.
*/
private Track getTrack() {
TripStatistics stats = new TripStatistics();
stats.setStartTime(TIME);
stats.setTotalTime(5000);
stats.setMovingTime(4000);
stats.setTotalDistance(20000);
stats.setMaxSpeed(1500);
stats.setTotalElevationGain(6000);
stats.setMinElevation(-500);
stats.setMaxElevation(550);
Track track = new Track();
track.setName("trackName");
track.setDescription("trackDescription");
track.setMapId("trackMapId");
track.setStatistics(stats);
return track;
}
/**
* Tests {@link SendDocsUtils#appendTag(StringBuilder, String, String)} with
* repeated calls.
*/
public void testAppendTag() {
StringBuilder stringBuilder = new StringBuilder();
SendDocsUtils.appendTag(stringBuilder, "name1", "value1");
assertEquals("<gsx:name1><![CDATA[value1]]></gsx:name1>", stringBuilder.toString());
SendDocsUtils.appendTag(stringBuilder, "name2", "value2");
assertEquals(
"<gsx:name1><![CDATA[value1]]></gsx:name1><gsx:name2><![CDATA[value2]]></gsx:name2>",
stringBuilder.toString());
}
/**
* Tests {@link SendDocsUtils#getDistance(double, boolean)} with metric units.
*/
public void testGetDistance_metric() {
assertEquals("1.22", SendDocsUtils.getDistance(1222.3, true));
}
/**
* Tests {@link SendDocsUtils#getDistance(double, boolean)} with imperial
* units.
*/
public void testGetDistance_imperial() {
assertEquals("0.76", SendDocsUtils.getDistance(1222.3, false));
}
/**
* Tests {@link SendDocsUtils#getSpeed(double, boolean)} with metric units.
*/
public void testGetSpeed_metric() {
assertEquals("15.55", SendDocsUtils.getSpeed(4.32, true));
}
/**
* Tests {@link SendDocsUtils#getSpeed(double, boolean)} with imperial units.
*/
public void testGetSpeed_imperial() {
assertEquals("9.66", SendDocsUtils.getSpeed(4.32, false));
}
/**
* Tests {@link SendDocsUtils#getElevation(double, boolean)} with metric
* units.
*/
public void testGetElevation_metric() {
assertEquals("3", SendDocsUtils.getElevation(3.456, true));
}
/**
* Tests {@link SendDocsUtils#getElevation(double, boolean)} with imperial
* units.
*/
public void testGetElevation_imperial() {
assertEquals("11", SendDocsUtils.getElevation(3.456, false));
}
}
@@ -0,0 +1,81 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.file;
/**
* Tests for {@link CsvTrackWriter}.
*
* @author Rodrigo Damazio
*/
public class CsvTrackWriterTest extends TrackFormatWriterTest {
private static final String BEGIN_TAG = "\"";
private static final String END_TAG = "\"\n";
private static final String SEPARATOR = "\",\"";
public void testCsvOutput() throws Exception {
String expectedTrackHeader = getExpectedLine(
"Track name", "Activity type", "Track description");
String expectedTrack = getExpectedLine(TRACK_NAME, TRACK_CATEGORY, TRACK_DESCRIPTION);
String expectedMarkerHeader = getExpectedLine("Marker name", "Marker type",
"Marker description", "Latitude (deg)", "Longitude (deg)", "Altitude (m)", "Bearing (deg)",
"Accuracy (m)", "Speed (m/s)", "Time");
String expectedMarker1 = getExpectedLine(WAYPOINT1_NAME, WAYPOINT1_CATEGORY,
WAYPOINT1_DESCRIPTION, "1.0", "-1.0", "10.0", "100.0", "1,000", "10,000",
"1970-01-01T00:01:40.000Z");
String expectedMarker2 = getExpectedLine(WAYPOINT2_NAME, WAYPOINT2_CATEGORY,
WAYPOINT2_DESCRIPTION, "2.0", "-2.0", "20.0", "200.0", "2,000", "20,000",
"1970-01-01T00:03:20.000Z");
String expectedPointHeader = getExpectedLine("Segment", "Point", "Latitude (deg)",
"Longitude (deg)", "Altitude (m)", "Bearing (deg)", "Accuracy (m)", "Speed (m/s)", "Time",
"Power (W)", "Cadence (rpm)", "Heart rate (bpm)", "Battery level (%)");
String expectedPoint1 = getExpectedLine("1", "1", "0.0", "0.0", "0.0", "0.0", "0", "0",
"1970-01-01T00:00:00.000Z", "100.0", "200.0", "300.0", "400.0");
String expectedPoint2 = getExpectedLine("1", "2", "1.0", "-1.0", "10.0", "100.0", "1,000",
"10,000", "1970-01-01T00:01:40.000Z", "101.0", "201.0", "301.0", "401.0");
String expectedPoint3 = getExpectedLine("2", "1", "2.0", "-2.0", "20.0", "200.0", "2,000",
"20,000", "1970-01-01T00:03:20.000Z", "102.0", "202.0", "302.0", "402.0");
String expectedPoint4 = getExpectedLine("2", "2", "3.0", "-3.0", "30.0", "300.0", "3,000",
"30,000", "1970-01-01T00:05:00.000Z", "103.0", "203.0", "303.0", "403.0");
String expected = expectedTrackHeader + expectedTrack + "\n"
+ expectedMarkerHeader + expectedMarker1 + expectedMarker2 + "\n"
+ expectedPointHeader + expectedPoint1 + expectedPoint2 + expectedPoint3 + expectedPoint4;
CsvTrackWriter writer = new CsvTrackWriter(getContext());
assertEquals(expected, writeTrack(writer));
}
/**
* Gets the expected CSV line from a list of expected values.
*
* @param values expected values
*/
private String getExpectedLine(String... values) {
StringBuilder builder = new StringBuilder();
builder.append(BEGIN_TAG);
boolean first = true;
for (String value : values) {
if (!first) {
builder.append(SEPARATOR);
}
first = false;
builder.append(value);
}
builder.append(END_TAG);
return builder.toString();
}
}
@@ -0,0 +1,295 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.file;
import static com.google.android.testing.mocking.AndroidMock.eq;
import static com.google.android.testing.mocking.AndroidMock.expect;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
import com.google.android.apps.mytracks.io.file.GpxImporter;
import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
import com.google.android.testing.mocking.AndroidMock;
import com.google.android.testing.mocking.UsesMocks;
import android.content.ContentUris;
import android.location.Location;
import android.location.LocationManager;
import android.net.Uri;
import android.test.AndroidTestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.SimpleTimeZone;
import javax.xml.parsers.ParserConfigurationException;
import org.easymock.Capture;
import org.easymock.IArgumentMatcher;
import org.xml.sax.SAXException;
/**
* Tests for the GPX importer.
*
* @author Steffen Horlacher
*/
public class GpxImporterTest extends AndroidTestCase {
private static final String TRACK_NAME = "blablub";
private static final String TRACK_DESC = "s'Laebe isch koi Schlotzer";
private static final String TRACK_LAT_1 = "48.768364";
private static final String TRACK_LON_1 = "9.177886";
private static final String TRACK_ELE_1 = "324.0";
private static final String TRACK_TIME_1 = "2010-04-22T18:21:00Z";
private static final String TRACK_LAT_2 = "48.768374";
private static final String TRACK_LON_2 = "9.177816";
private static final String TRACK_ELE_2 = "333.0";
private static final String TRACK_TIME_2 = "2010-04-22T18:21:50.123";
private static final SimpleDateFormat DATE_FORMAT1 =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
private static final SimpleDateFormat DATE_FORMAT2 =
new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
static {
// We can't omit the timezones in the test, otherwise it'll use the local
// timezone and fail depending on where the test runner is.
SimpleTimeZone utc = new SimpleTimeZone(0, "UTC");
DATE_FORMAT1.setTimeZone(utc);
DATE_FORMAT2.setTimeZone(utc);
}
// TODO: use real files from different sources with more track points.
private static final String VALID_TEST_GPX = "<gpx><trk><name><![CDATA["
+ TRACK_NAME + "]]></name><desc><![CDATA[" + TRACK_DESC
+ "]]></desc><trkseg>" + "<trkpt lat=\"" + TRACK_LAT_1 + "\" lon=\""
+ TRACK_LON_1 + "\"><ele>" + TRACK_ELE_1 + "</ele><time>" + TRACK_TIME_1
+ "</time></trkpt> +" + "<trkpt lat=\"" + TRACK_LAT_2 + "\" lon=\""
+ TRACK_LON_2 + "\"><ele>" + TRACK_ELE_2 + "</ele><time>" + TRACK_TIME_2
+ "</time></trkpt>" + "</trkseg></trk></gpx>";
// invalid xml
private static final String INVALID_XML_TEST_GPX = VALID_TEST_GPX.substring(
0, VALID_TEST_GPX.length() - 50);
private static final String INVALID_LOCATION_TEST_GPX = VALID_TEST_GPX
.replaceAll(TRACK_LAT_1, "1000.0");
private static final String INVALID_TIME_TEST_GPX = VALID_TEST_GPX
.replaceAll(TRACK_TIME_1, "invalid");
private static final String INVALID_ALTITUDE_TEST_GPX = VALID_TEST_GPX
.replaceAll(TRACK_ELE_1, "invalid");
private static final String INVALID_LATITUDE_TEST_GPX = VALID_TEST_GPX
.replaceAll(TRACK_LAT_1, "invalid");
private static final String INVALID_LONGITUDE_TEST_GPX = VALID_TEST_GPX
.replaceAll(TRACK_LON_1, "invalid");
private static final long TRACK_ID = 1;
private static final long TRACK_POINT_ID_1 = 1;
private static final long TRACK_POINT_ID_2 = 2;
private static final Uri TRACK_ID_URI = ContentUris.appendId(
TracksColumns.CONTENT_URI.buildUpon(), TRACK_ID).build();
private MyTracksProviderUtils providerUtils;
private Factory oldProviderUtilsFactory;
@UsesMocks(MyTracksProviderUtils.class)
@Override
protected void setUp() throws Exception {
super.setUp();
providerUtils = AndroidMock.createMock(MyTracksProviderUtils.class);
oldProviderUtilsFactory =
TestingProviderUtilsFactory.installWithInstance(providerUtils);
}
@Override
protected void tearDown() throws Exception {
TestingProviderUtilsFactory.restoreOldFactory(oldProviderUtilsFactory);
super.tearDown();
}
/**
* Test import success.
*/
public void testImportSuccess() throws Exception {
Capture<Track> trackParam = new Capture<Track>();
Location loc1 = new Location(LocationManager.GPS_PROVIDER);
loc1.setTime(DATE_FORMAT2.parse(TRACK_TIME_1).getTime());
loc1.setLatitude(Double.parseDouble(TRACK_LAT_1));
loc1.setLongitude(Double.parseDouble(TRACK_LON_1));
loc1.setAltitude(Double.parseDouble(TRACK_ELE_1));
Location loc2 = new Location(LocationManager.GPS_PROVIDER);
loc2.setTime(DATE_FORMAT1.parse(TRACK_TIME_2).getTime());
loc2.setLatitude(Double.parseDouble(TRACK_LAT_2));
loc2.setLongitude(Double.parseDouble(TRACK_LON_2));
loc2.setAltitude(Double.parseDouble(TRACK_ELE_2));
expect(providerUtils.insertTrack(AndroidMock.capture(trackParam)))
.andReturn(TRACK_ID_URI);
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(TRACK_POINT_ID_1).andReturn(TRACK_POINT_ID_2);
// A flush happens after the first insertion to get the starting point ID,
// which is why we get two calls
expect(providerUtils.bulkInsertTrackPoints(LocationsMatcher.eqLoc(loc1),
eq(1), eq(TRACK_ID))).andReturn(1);
expect(providerUtils.bulkInsertTrackPoints(LocationsMatcher.eqLoc(loc2),
eq(1), eq(TRACK_ID))).andReturn(1);
providerUtils.updateTrack(AndroidMock.capture(trackParam));
AndroidMock.replay(providerUtils);
InputStream is = new ByteArrayInputStream(VALID_TEST_GPX.getBytes());
GpxImporter.importGPXFile(is, providerUtils);
AndroidMock.verify(providerUtils);
// verify track parameter
Track track = trackParam.getValue();
assertEquals(TRACK_NAME, track.getName());
assertEquals(TRACK_DESC, track.getDescription());
assertEquals(DATE_FORMAT2.parse(TRACK_TIME_1).getTime(), track.getStatistics()
.getStartTime());
assertNotSame(-1, track.getStartId());
assertNotSame(-1, track.getStopId());
}
/**
* Test with invalid location - track should be deleted.
*/
public void testImportLocationFailure() throws ParserConfigurationException, IOException {
testInvalidXML(INVALID_LOCATION_TEST_GPX);
}
/**
* Test with invalid time - track should be deleted.
*/
public void testImportTimeFailure() throws ParserConfigurationException, IOException {
testInvalidXML(INVALID_TIME_TEST_GPX);
}
/**
* Test with invalid xml - track should be deleted.
*/
public void testImportXMLFailure() throws ParserConfigurationException, IOException {
testInvalidXML(INVALID_XML_TEST_GPX);
}
/**
* Test with invalid altitude - track should be deleted.
*/
public void testImportInvalidAltitude() throws ParserConfigurationException, IOException {
testInvalidXML(INVALID_ALTITUDE_TEST_GPX);
}
/**
* Test with invalid latitude - track should be deleted.
*/
public void testImportInvalidLatitude() throws ParserConfigurationException, IOException {
testInvalidXML(INVALID_LATITUDE_TEST_GPX);
}
/**
* Test with invalid longitude - track should be deleted.
*/
public void testImportInvalidLongitude() throws ParserConfigurationException, IOException {
testInvalidXML(INVALID_LONGITUDE_TEST_GPX);
}
private void testInvalidXML(String xml) throws ParserConfigurationException,
IOException {
expect(providerUtils.insertTrack((Track) AndroidMock.anyObject()))
.andReturn(TRACK_ID_URI);
expect(providerUtils.bulkInsertTrackPoints((Location[]) AndroidMock.anyObject(),
AndroidMock.anyInt(), AndroidMock.anyLong())).andStubReturn(1);
expect(providerUtils.getLastLocationId(TRACK_ID)).andStubReturn(TRACK_POINT_ID_1);
providerUtils.deleteTrack(TRACK_ID);
AndroidMock.replay(providerUtils);
InputStream is = new ByteArrayInputStream(xml.getBytes());
try {
GpxImporter.importGPXFile(is, providerUtils);
} catch (SAXException e) {
// expected exception
}
AndroidMock.verify(providerUtils);
}
/**
* Workaround because of capture bug 2617107 in easymock:
* http://sourceforge.net
* /tracker/?func=detail&aid=2617107&group_id=82958&atid=567837
*/
private static class LocationsMatcher implements IArgumentMatcher {
private final Location[] matchLocs;
private LocationsMatcher(Location[] expected) {
this.matchLocs = expected;
}
public static Location[] eqLoc(Location[] expected) {
IArgumentMatcher matcher = new LocationsMatcher(expected);
AndroidMock.reportMatcher(matcher);
return null;
}
public static Location[] eqLoc(Location expected) {
return eqLoc(new Location[] { expected});
}
@Override
public void appendTo(StringBuffer buf) {
buf.append("eqLoc(").append(Arrays.toString(matchLocs)).append(")");
}
@Override
public boolean matches(Object obj) {
if (! (obj instanceof Location[])) { return false; }
Location[] locs = (Location[]) obj;
if (locs.length < matchLocs.length) { return false; }
// Only check the first elements (those that will be taken into account)
for (int i = 0; i < matchLocs.length; i++) {
if (!locationsMatch(locs[i], matchLocs[i])) {
return false;
}
}
return true;
}
private boolean locationsMatch(Location loc1, Location loc2) {
return (loc1.getTime() == loc2.getTime()) &&
(loc1.getLatitude() == loc2.getLatitude()) &&
(loc1.getLongitude() == loc2.getLongitude()) &&
(loc1.getAltitude() == loc2.getAltitude());
}
}
}
@@ -0,0 +1,76 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.file;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Tests for {@link GpxTrackWriter}.
*
* @author Rodrigo Damazio
*/
public class GpxTrackWriterTest extends TrackFormatWriterTest {
public void testXmlOutput() throws Exception {
TrackFormatWriter writer = new GpxTrackWriter(getContext());
String result = writeTrack(writer);
Document doc = parseXmlDocument(result);
Element gpxTag = getChildElement(doc, "gpx");
Element trackTag = getChildElement(gpxTag, "trk");
assertEquals(TRACK_NAME, getChildTextValue(trackTag, "name"));
assertEquals(TRACK_DESCRIPTION, getChildTextValue(trackTag, "desc"));
List<Element> segmentTags = getChildElements(trackTag, "trkseg", 2);
List<Element> segPointTags = getChildElements(segmentTags.get(0), "trkpt", 2);
assertTagMatchesLocation(segPointTags.get(0), "0", "0", "1970-01-01T00:00:00.000Z", "0");
assertTagMatchesLocation(segPointTags.get(1), "1", "-1", "1970-01-01T00:01:40.000Z", "10");
segPointTags = getChildElements(segmentTags.get(1), "trkpt", 2);
assertTagMatchesLocation(segPointTags.get(0), "2", "-2", "1970-01-01T00:03:20.000Z", "20");
assertTagMatchesLocation(segPointTags.get(1), "3", "-3", "1970-01-01T00:05:00.000Z", "30");
List<Element> waypointTags = getChildElements(gpxTag, "wpt", 2);
Element wptTag = waypointTags.get(0);
assertEquals(WAYPOINT1_NAME, getChildTextValue(wptTag, "name"));
assertEquals(WAYPOINT1_DESCRIPTION, getChildTextValue(wptTag, "desc"));
assertTagMatchesLocation(wptTag, "1", "-1", "1970-01-01T00:01:40.000Z", "10");
wptTag = waypointTags.get(1);
assertEquals(WAYPOINT2_NAME, getChildTextValue(wptTag, "name"));
assertEquals(WAYPOINT2_DESCRIPTION, getChildTextValue(wptTag, "desc"));
assertTagMatchesLocation(wptTag, "2", "-2", "1970-01-01T00:03:20.000Z", "20");
}
/**
* Asserts that the given tag describes a location.
*
* @param tag the tag
* @param latitude the location's latitude
* @param longitude the location's longitude
* @param time the location's time
* @param elevation the location's elevation
*/
private void assertTagMatchesLocation(
Element tag, String latitude, String longitude, String time, String elevation) {
assertEquals(latitude, tag.getAttribute("lat"));
assertEquals(longitude, tag.getAttribute("lon"));
assertEquals(time, getChildTextValue(tag, "time"));
assertEquals(elevation, getChildTextValue(tag, "ele"));
}
}
@@ -0,0 +1,125 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.DescriptionGenerator;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import android.location.Location;
import java.util.List;
import java.util.Vector;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Tests for {@link KmlTrackWriter}.
*
* @author Rodrigo Damazio
*/
public class KmlTrackWriterTest extends TrackFormatWriterTest {
private static final String FULL_TRACK_DESCRIPTION = "full track description";
/**
* A fake version of {@link DescriptionGenerator} which returns a fixed track
* description, thus not depending on the context.
*/
private class FakeDescriptionGenerator implements DescriptionGenerator {
@Override
public String generateTrackDescription(
Track aTrack, Vector<Double> distances, Vector<Double> elevations) {
return FULL_TRACK_DESCRIPTION;
}
@Override
public String generateWaypointDescription(Waypoint waypoint) {
return null;
}
}
public void testXmlOutput() throws Exception {
KmlTrackWriter writer = new KmlTrackWriter(getContext(), new FakeDescriptionGenerator());
String result = writeTrack(writer);
Document doc = parseXmlDocument(result);
Element kmlTag = getChildElement(doc, "kml");
Element docTag = getChildElement(kmlTag, "Document");
assertEquals(TRACK_NAME, getChildTextValue(docTag, "name"));
assertEquals(TRACK_DESCRIPTION, getChildTextValue(docTag, "description"));
// There are 3 placemarks - start, track, and end
List<Element> placemarkTags = getChildElements(docTag, "Placemark", 3);
assertTagIsPlacemark(
placemarkTags.get(0), TRACK_NAME + " (Start)", TRACK_DESCRIPTION, location1);
assertTagIsPlacemark(
placemarkTags.get(2), TRACK_NAME + " (End)", FULL_TRACK_DESCRIPTION, location4);
List<Element> folderTag = getChildElements(docTag, "Folder", 1);
List<Element> folderPlacemarkTags = getChildElements(folderTag.get(0), "Placemark", 2);
assertTagIsPlacemark(
folderPlacemarkTags.get(0), WAYPOINT1_NAME, WAYPOINT1_DESCRIPTION, location2);
assertTagIsPlacemark(
folderPlacemarkTags.get(1), WAYPOINT2_NAME, WAYPOINT2_DESCRIPTION, location3);
Element trackPlacemarkTag = placemarkTags.get(1);
assertEquals(TRACK_NAME, getChildTextValue(trackPlacemarkTag, "name"));
assertEquals(TRACK_DESCRIPTION, getChildTextValue(trackPlacemarkTag, "description"));
Element multiTrackTag = getChildElement(trackPlacemarkTag, "gx:MultiTrack");
List<Element> trackTags = getChildElements(multiTrackTag, "gx:Track", 2);
assertTagHasPoints(trackTags.get(0), location1, location2);
assertTagHasPoints(trackTags.get(1), location3, location4);
}
/**
* Asserts that the given tag is a placemark with the given properties.
*
* @param tag the tag
* @param name the expected placemark name
* @param description the expected placemark description
* @param location the expected placemark location
*/
private void assertTagIsPlacemark(
Element tag, String name, String description, Location location) {
assertEquals(name, getChildTextValue(tag, "name"));
assertEquals(description, getChildTextValue(tag, "description"));
Element pointTag = getChildElement(tag, "Point");
String expected = location.getLongitude() + "," + location.getLatitude() + ","
+ location.getAltitude();
String actual = getChildTextValue(pointTag, "coordinates");
assertEquals(expected, actual);
}
/**
* Asserts that the given tag has a list of "gx:coord" subtags matching the
* expected locations.
*
* @param tag the parent tag
* @param locations list of expected locations
*/
private void assertTagHasPoints(Element tag, Location... locations) {
List<Element> coordTags = getChildElements(tag, "gx:coord", locations.length);
for (int i = 0; i < locations.length; i++) {
Location location = locations[i];
String expected = location.getLongitude() + " " + location.getLatitude() + " "
+ location.getAltitude();
String actual = coordTags.get(i).getFirstChild().getTextContent();
assertEquals(expected, actual);
}
}
}
@@ -0,0 +1,64 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.file;
import java.io.File;
/**
* A simple, fake {@link TrackWriter} subclass with all methods mocked out.
* Tests are expected to override {@link #writeTrack}.
*
* @author Matthew Simmons
*
*/
public class MockTrackWriter implements TrackWriter {
public OnWriteListener onWriteListener;
@Override
public void setOnWriteListener(OnWriteListener onWriteListener) {
this.onWriteListener = onWriteListener;
}
@Override
public void setDirectory(File directory) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public String getAbsolutePath() {
throw new UnsupportedOperationException("not implemented");
}
@Override
public void writeTrack() {
throw new UnsupportedOperationException("not implemented");
}
@Override
public void stopWriteTrack() {
throw new UnsupportedOperationException("not implemented");
}
@Override
public boolean wasSuccess() {
return false;
}
@Override
public int getErrorMessage() {
return 0;
}
}
@@ -0,0 +1,96 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.util.StringUtils;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Tests for {@link TcxTrackWriter}.
*
* @author Sandor Dornbush
*/
public class TcxTrackWriterTest extends TrackFormatWriterTest {
public void testXmlOutput() throws Exception {
TrackFormatWriter writer = new TcxTrackWriter(getContext());
String result = writeTrack(writer);
Document doc = parseXmlDocument(result);
Element root = getChildElement(doc, "TrainingCenterDatabase");
Element activitiesTag = getChildElement(root, "Activities");
Element activityTag = getChildElement(activitiesTag, "Activity");
Element lapTag = getChildElement(activityTag, "Lap");
List<Element> segmentTags = getChildElements(lapTag, "Track", 2);
Element segment1Tag = segmentTags.get(0);
Element segment2Tag = segmentTags.get(1);
List<Element> seg1PointTags = getChildElements(segment1Tag, "Trackpoint", 2);
List<Element> seg2PointTags = getChildElements(segment2Tag, "Trackpoint", 2);
assertTagsMatchPoints(seg1PointTags, location1, location2);
assertTagsMatchPoints(seg2PointTags, location3, location4);
}
/**
* Asserts that the given tags describe the given locations in the same order.
*
* @param tags list of tags
* @param locations list of locations
*/
private void assertTagsMatchPoints(List<Element> tags, MyTracksLocation... locations) {
assertEquals(locations.length, tags.size());
for (int i = 0; i < locations.length; i++) {
assertTagMatchesLocation(tags.get(i), locations[i]);
}
}
/**
* Asserts that the given tag describes the given location.
*
* @param tag the tag
* @param location the location
*/
private void assertTagMatchesLocation(Element tag, MyTracksLocation location) {
assertEquals(StringUtils.formatDateTimeIso8601(location.getTime()), getChildTextValue(tag, "Time"));
Element positionTag = getChildElement(tag, "Position");
assertEquals(
Double.toString(location.getLatitude()), getChildTextValue(positionTag, "LatitudeDegrees"));
assertEquals(Double.toString(location.getLongitude()),
getChildTextValue(positionTag, "LongitudeDegrees"));
assertEquals(Double.toString(location.getAltitude()), getChildTextValue(tag, "AltitudeMeters"));
assertTrue(location.getSensorDataSet() != null);
Sensor.SensorDataSet sds = location.getSensorDataSet();
List<Element> heartRate = getChildElements(tag, "HeartRateBpm", 1);
assertEquals(Integer.toString(sds.getHeartRate().getValue()),
getChildTextValue(heartRate.get(0), "Value"));
List<Element> extensions = getChildElements(tag, "Extensions", 1);
List<Element> tpx = getChildElements(extensions.get(0), "TPX", 1);
assertEquals(
Integer.toString(sds.getCadence().getValue()), getChildTextValue(tpx.get(0), "RunCadence"));
assertEquals(
Integer.toString(sds.getPower().getValue()), getChildTextValue(tpx.get(0), "Watts"));
}
}
@@ -0,0 +1,219 @@
// Copyright 2010 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import android.test.AndroidTestCase;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Base class for track format writer tests, which sets up a fake track and
* gives auxiliary methods for verifying XML output.
*
* @author Rodrigo Damazio
*/
public abstract class TrackFormatWriterTest extends AndroidTestCase {
// All the user-provided strings have "]]>" to ensure that proper escaping is
// being done.
protected static final String TRACK_NAME = "Home]]>";
protected static final String TRACK_CATEGORY = "Hiking";
protected static final String TRACK_DESCRIPTION = "The long ]]> journey home";
protected static final String WAYPOINT1_NAME = "point]]>1";
protected static final String WAYPOINT1_CATEGORY = "Statistics";
protected static final String WAYPOINT1_DESCRIPTION = "point 1]]>description";
protected static final String WAYPOINT2_NAME = "point]]>2";
protected static final String WAYPOINT2_CATEGORY = "Waypoint";
protected static final String WAYPOINT2_DESCRIPTION = "point 2]]>description";
private static final int BUFFER_SIZE = 10240;
protected Track track;
protected MyTracksLocation location1, location2, location3, location4;
protected Waypoint wp1, wp2;
@Override
protected void setUp() throws Exception {
super.setUp();
track = new Track();
track.setName(TRACK_NAME);
track.setCategory(TRACK_CATEGORY);
track.setDescription(TRACK_DESCRIPTION);
location1 = new MyTracksLocation("mock");
location2 = new MyTracksLocation("mock");
location3 = new MyTracksLocation("mock");
location4 = new MyTracksLocation("mock");
populateLocations(location1, location2, location3, location4);
wp1 = new Waypoint();
wp2 = new Waypoint();
wp1.setLocation(location2);
wp1.setName(WAYPOINT1_NAME);
wp1.setCategory(WAYPOINT1_CATEGORY);
wp1.setDescription(WAYPOINT1_DESCRIPTION);
wp2.setLocation(location3);
wp2.setName(WAYPOINT2_NAME);
wp2.setCategory(WAYPOINT2_CATEGORY);
wp2.setDescription(WAYPOINT2_DESCRIPTION);
}
/**
* Populates a list of locations with values.
*
* @param locations a list of locations
*/
private void populateLocations(MyTracksLocation... locations) {
for (int i = 0; i < locations.length; i++) {
MyTracksLocation location = locations[i];
location.setLatitude(i);
location.setLongitude(-i);
location.setAltitude(i * 10);
location.setBearing(i * 100);
location.setAccuracy(i * 1000);
location.setSpeed(i * 10000);
location.setTime(i * 100000);
Sensor.SensorData.Builder power = Sensor.SensorData.newBuilder().setValue(100 + i)
.setState(Sensor.SensorState.SENDING);
Sensor.SensorData.Builder cadence = Sensor.SensorData.newBuilder().setValue(200 + i)
.setState(Sensor.SensorState.SENDING);
Sensor.SensorData.Builder heartRate = Sensor.SensorData.newBuilder().setValue(300 + i)
.setState(Sensor.SensorState.SENDING);
Sensor.SensorData.Builder batteryLevel = Sensor.SensorData.newBuilder().setValue(400 + i)
.setState(Sensor.SensorState.SENDING);
Sensor.SensorDataSet sensorDataSet = Sensor.SensorDataSet.newBuilder().setPower(power)
.setCadence(cadence).setHeartRate(heartRate).setBatteryLevel(batteryLevel).build();
location.setSensorData(sensorDataSet);
}
}
/**
* Makes the right sequence of calls to the writer in order to write the fake
* track in {@link #track}.
*
* @param writer the writer to write to
* @return the written contents
*/
protected String writeTrack(TrackFormatWriter writer) throws Exception {
OutputStream output = new ByteArrayOutputStream(BUFFER_SIZE);
writer.prepare(track, output);
writer.writeHeader();
writer.writeBeginWaypoints();
writer.writeWaypoint(wp1);
writer.writeWaypoint(wp2);
writer.writeEndWaypoints();
writer.writeBeginTrack(location1);
writer.writeOpenSegment();
writer.writeLocation(location1);
writer.writeLocation(location2);
writer.writeCloseSegment();
writer.writeOpenSegment();
writer.writeLocation(location3);
writer.writeLocation(location4);
writer.writeCloseSegment();
writer.writeEndTrack(location4);
writer.writeFooter();
writer.close();
return output.toString();
}
/**
* Gets the text data contained inside a tag.
*
* @param parent the parent of the tag containing the text
* @param elementName the name of the tag containing the text
* @return the text contents
*/
protected String getChildTextValue(Element parent, String elementName) {
Element child = getChildElement(parent, elementName);
assertTrue(child.hasChildNodes());
NodeList children = child.getChildNodes();
int length = children.getLength();
assertTrue(length > 0);
// The children may be a sucession of text elements, just concatenate them
String result = "";
for (int i = 0; i < length; i++) {
Text textNode = (Text) children.item(i);
result += textNode.getNodeValue();
}
return result;
}
/**
* Returns all child elements of a given parent which have the given name.
*
* @param parent the parent to get children from
* @param elementName the element name to look for
* @param expectedChildren the number of children we're expected to find
* @return a list of the found elements
*/
protected List<Element> getChildElements(Node parent, String elementName,
int expectedChildren) {
assertTrue(parent.hasChildNodes());
NodeList children = parent.getChildNodes();
int length = children.getLength();
List<Element> result = new ArrayList<Element>();
for (int i = 0; i < length; i++) {
Node childNode = children.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE
&& childNode.getNodeName().equalsIgnoreCase(elementName)) {
result.add((Element) childNode);
}
}
assertTrue(children.toString(), result.size() == expectedChildren);
return result;
}
/**
* Returns the single child element of the given parent with the given type.
*
* @param parent the parent to get a child from
* @param elementName the name of the child to look for
* @return the child element
*/
protected Element getChildElement(Node parent, String elementName) {
return getChildElements(parent, elementName, 1).get(0);
}
/**
* Parses the given XML contents and returns a DOM {@link Document} for it.
*/
protected Document parseXmlDocument(String contents)
throws FactoryConfigurationError, ParserConfigurationException,
SAXException, IOException {
DocumentBuilderFactory builderFactory =
DocumentBuilderFactory.newInstance();
builderFactory.setCoalescing(true);
// TODO: Somehow do XML validation on Android
// builderFactory.setValidating(true);
builderFactory.setNamespaceAware(true);
builderFactory.setIgnoringComments(true);
builderFactory.setIgnoringElementContentWhitespace(true);
DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
Document doc = documentBuilder.parse(
new InputSource(new StringReader(contents)));
return doc;
}
}
@@ -0,0 +1,363 @@
// Copyright 2010 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.file;
import static org.easymock.EasyMock.expect;
import com.google.android.apps.mytracks.content.MyTracksProvider;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
import android.content.Context;
import android.location.Location;
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.test.mock.MockContentResolver;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.OutputStream;
import org.easymock.EasyMock;
import org.easymock.IArgumentMatcher;
import org.easymock.IMocksControl;
/**
* Tests for the track writer.
*
* @author Rodrigo Damazio
*/
public class TrackWriterTest extends AndroidTestCase {
/**
* {@link TrackWriterImpl} subclass which mocks out methods called from
* {@link TrackWriterImpl#openFile}.
*/
private static final class OpenFileTrackWriter extends TrackWriterImpl {
private final ByteArrayOutputStream stream;
private final boolean canWrite;
/**
* Constructor.
*
* @param stream the stream to return from
* {@link TrackWriterImpl#newOutputStream}, or null to throw a
* {@link FileNotFoundException}
* @param canWrite the value that {@link TrackWriterImpl#canWriteFile} will
* return
*/
private OpenFileTrackWriter(Context context,
MyTracksProviderUtils providerUtils, Track track,
TrackFormatWriter writer, ByteArrayOutputStream stream,
boolean canWrite) {
super(context, providerUtils, track, writer);
this.stream = stream;
this.canWrite = canWrite;
// The directory is set in the canWriteFile. However, this class
// overwrites canWriteFile, thus needs to set it.
setDirectory(new File("/"));
}
@Override
protected boolean canWriteFile() {
return canWrite;
}
@Override
protected OutputStream newOutputStream(String fileName)
throws FileNotFoundException {
assertEquals(FULL_TRACK_NAME, fileName);
if (stream == null) {
throw new FileNotFoundException();
}
return stream;
}
}
/**
* {@link TrackWriterImpl} subclass which mocks out methods called from
* {@link TrackWriterImpl#writeTrack}.
*/
private final class WriteTracksTrackWriter extends TrackWriterImpl {
private final boolean openResult;
/**
* Constructor.
*
* @param openResult the return value for {@link TrackWriterImpl#openFile}
*/
private WriteTracksTrackWriter(Context context,
MyTracksProviderUtils providerUtils, Track track,
TrackFormatWriter writer, boolean openResult) {
super(context, providerUtils, track, writer);
this.openResult = openResult;
}
@Override
protected boolean openFile() {
openFileCalls++;
return openResult;
}
@Override
void writeDocument() {
writeDocumentCalls++;
}
@Override
protected void runOnUiThread(Runnable runnable) {
runnable.run();
}
}
private static final long TRACK_ID = 1234567L;
private static final String EXTENSION = "ext";
private static final String TRACK_NAME = "Swimming across the pacific";
private static final String FULL_TRACK_NAME =
"Swimming across the pacific.ext";
private Track track;
private TrackFormatWriter formatWriter;
private TrackWriterImpl writer;
private IMocksControl mocksControl;
private MyTracksProviderUtils providerUtils;
private Factory oldProviderUtilsFactory;
// State used in specific tests
private int writeDocumentCalls;
private int openFileCalls;
@Override
protected void setUp() throws Exception {
super.setUp();
MockContentResolver mockContentResolver = new MockContentResolver();
RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
getContext(), getContext(), "test.");
Context context = new MockContext(mockContentResolver, targetContext);
MyTracksProvider provider = new MyTracksProvider();
provider.attachInfo(context, null);
mockContentResolver.addProvider(MyTracksProviderUtils.AUTHORITY, provider);
setContext(context);
providerUtils = MyTracksProviderUtils.Factory.get(context);
oldProviderUtilsFactory = TestingProviderUtilsFactory.installWithInstance(providerUtils);
mocksControl = EasyMock.createStrictControl();
formatWriter = mocksControl.createMock(TrackFormatWriter.class);
expect(formatWriter.getExtension()).andStubReturn(EXTENSION);
track = new Track();
track.setName(TRACK_NAME);
track.setId(TRACK_ID);
}
@Override
protected void tearDown() throws Exception {
TestingProviderUtilsFactory.restoreOldFactory(oldProviderUtilsFactory);
super.tearDown();
}
public void testWriteTrack() {
writer = new WriteTracksTrackWriter(getContext(), providerUtils, track,
formatWriter, true);
mocksControl.replay();
writer.writeTrack();
assertEquals(1, writeDocumentCalls);
assertEquals(1, openFileCalls);
mocksControl.verify();
}
public void testWriteTrack_openFails() {
writer = new WriteTracksTrackWriter(getContext(), providerUtils, track,
formatWriter, false);
mocksControl.replay();
writer.writeTrack();
assertEquals(0, writeDocumentCalls);
assertEquals(1, openFileCalls);
mocksControl.verify();
}
public void testOpenFile() {
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
writer = new OpenFileTrackWriter(
getContext(), providerUtils, track, formatWriter, stream, true);
formatWriter.prepare(track, stream);
mocksControl.replay();
assertTrue(writer.openFile());
mocksControl.verify();
}
public void testOpenFile_cantWrite() {
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
writer = new OpenFileTrackWriter(
getContext(), providerUtils, track, formatWriter, stream, false);
mocksControl.replay();
assertFalse(writer.openFile());
mocksControl.verify();
}
public void testOpenFile_streamError() {
writer = new OpenFileTrackWriter(
getContext(), providerUtils, track, formatWriter, null, true);
mocksControl.replay();
assertFalse(writer.openFile());
mocksControl.verify();
}
public void testWriteDocument_emptyTrack() throws Exception {
writer = new TrackWriterImpl(getContext(), providerUtils, track, formatWriter);
// Set expected mock behavior
formatWriter.writeHeader();
formatWriter.writeFooter();
formatWriter.close();
mocksControl.replay();
writer.writeDocument();
assertTrue(writer.wasSuccess());
mocksControl.verify();
}
public void testWriteDocument() throws Exception {
writer = new TrackWriterImpl(getContext(), providerUtils, track, formatWriter);
final Location[] locs = {
new Location("fake0"),
new Location("fake1"),
new Location("fake2"),
new Location("fake3"),
new Location("fake4"),
new Location("fake5")
};
Waypoint[] wps = { new Waypoint(), new Waypoint(), new Waypoint() };
// Fill locations with valid values
fillLocations(locs);
// Make location 3 invalid
locs[2].setLatitude(100);
assertEquals(locs.length, providerUtils.bulkInsertTrackPoints(locs, locs.length, TRACK_ID));
for (int i = 0; i < wps.length; ++i) {
Waypoint wpt = wps[i];
wpt.setTrackId(TRACK_ID);
assertNotNull(providerUtils.insertWaypoint(wpt));
wpt.setId(i + 1);
}
formatWriter.writeHeader();
// Expect reading/writing of the waypoints (except the first)
formatWriter.writeBeginWaypoints();
formatWriter.writeWaypoint(wptEq(wps[1]));
formatWriter.writeWaypoint(wptEq(wps[2]));
formatWriter.writeEndWaypoints();
// Begin the track
formatWriter.writeBeginTrack(locEq(locs[0]));
// Write locations 1-2
formatWriter.writeOpenSegment();
formatWriter.writeLocation(locEq(locs[0]));
formatWriter.writeLocation(locEq(locs[1]));
formatWriter.writeCloseSegment();
// Location 3 is not written - it's invalid
// Write locations 4-6
formatWriter.writeOpenSegment();
formatWriter.writeLocation(locEq(locs[3]));
formatWriter.writeLocation(locEq(locs[4]));
formatWriter.writeLocation(locEq(locs[5]));
formatWriter.writeCloseSegment();
// End the track
formatWriter.writeEndTrack(locEq(locs[5]));
formatWriter.writeFooter();
formatWriter.close();
mocksControl.replay();
writer.writeDocument();
assertTrue(writer.wasSuccess());
mocksControl.verify();
}
private static Waypoint wptEq(final Waypoint wpt) {
EasyMock.reportMatcher(new IArgumentMatcher() {
@Override
public boolean matches(Object wptObj2) {
if (wptObj2 == null || wpt == null) return wpt == wptObj2;
Waypoint wpt2 = (Waypoint) wptObj2;
return wpt.getId() == wpt2.getId();
}
@Override
public void appendTo(StringBuffer buffer) {
buffer.append("wptEq(");
buffer.append(wpt);
buffer.append(")");
}
});
return null;
}
private static Location locEq(final Location loc) {
EasyMock.reportMatcher(new IArgumentMatcher() {
@Override
public boolean matches(Object locObj2) {
if (locObj2 == null || loc == null) return loc == locObj2;
Location loc2 = (Location) locObj2;
return loc.hasAccuracy() == loc2.hasAccuracy()
&& (!loc.hasAccuracy() || loc.getAccuracy() == loc2.getAccuracy())
&& loc.hasAltitude() == loc2.hasAltitude()
&& (!loc.hasAltitude() || loc.getAltitude() == loc2.getAltitude())
&& loc.hasBearing() == loc2.hasBearing()
&& (!loc.hasBearing() || loc.getBearing() == loc2.getBearing())
&& loc.hasSpeed() == loc2.hasSpeed()
&& (!loc.hasSpeed() || loc.getSpeed() == loc2.getSpeed())
&& loc.getLatitude() == loc2.getLatitude()
&& loc.getLongitude() == loc2.getLongitude()
&& loc.getTime() == loc2.getTime();
}
@Override
public void appendTo(StringBuffer buffer) {
buffer.append("locEq(");
buffer.append(loc);
buffer.append(")");
}
});
return null;
}
private void fillLocations(Location... locs) {
assertTrue(locs.length < 90);
for (int i = 0; i < locs.length; i++) {
Location location = locs[i];
location.setLatitude(i + 1);
location.setLongitude(i + 1);
location.setTime(i + 1000);
}
}
}
@@ -0,0 +1,85 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.fusiontables;
import com.google.android.apps.mytracks.io.docs.SendDocsActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity;
import android.test.AndroidTestCase;
/**
* Tests the {@link SendFusionTablesActivity}.
*
* @author Youtao Liu
*/
public class SendFusionTablesActivityTest extends AndroidTestCase {
private SendFusionTablesActivity sendFusionTablesActivity;
private SendRequest sendRequest;
@Override
protected void setUp() throws Exception {
super.setUp();
sendRequest = new SendRequest(1L, true, false, true);
sendFusionTablesActivity = new SendFusionTablesActivity();
}
/**
* Tests the method
* {@link SendFusionTablesActivity#getNextClass(SendRequest, boolean)}. Sets
* the flags of "sendDocs" and "cancel" to false and false.
*/
public void testGetNextClass_notCancelNotSendDocs() {
sendRequest.setSendDocs(false);
Class<?> next = sendFusionTablesActivity.getNextClass(sendRequest, false);
assertEquals(UploadResultActivity.class, next);
}
/**
* Tests the method
* {@link SendFusionTablesActivity#getNextClass(SendRequest, boolean)}. Sets
* the flags of "sendDocs" and "cancel" to true and false.
*/
public void testGetNextClass_notCancelSendDocs() {
sendRequest.setSendDocs(true);
Class<?> next = sendFusionTablesActivity.getNextClass(sendRequest, false);
assertEquals(SendDocsActivity.class, next);
}
/**
* Tests the method
* {@link SendFusionTablesActivity#getNextClass(SendRequest,boolean)}. Sets
* the flags of "sendDocs" and "cancel" to true and true.
*/
public void testGetNextClass_cancelSendDocs() {
sendRequest.setSendDocs(true);
Class<?> next = sendFusionTablesActivity.getNextClass(sendRequest, true);
assertEquals(UploadResultActivity.class, next);
}
/**
* Tests the method
* {@link SendFusionTablesActivity#getNextClass(SendRequest,boolean)}. Sets
* the flags of "sendDocs" and "cancel" to false and true.
*/
public void testGetNextClass_cancelNotSendDocs() {
sendRequest.setSendDocs(false);
Class<?> next = sendFusionTablesActivity.getNextClass(sendRequest, true);
assertEquals(UploadResultActivity.class, next);
}
}
@@ -0,0 +1,285 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.fusiontables;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.stats.TripStatistics;
import android.location.Location;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import junit.framework.TestCase;
/**
* Tests {@link SendFusionTablesUtils}.
*
* @author Jimmy Shih
*/
public class SendFusionTablesUtilsTest extends TestCase {
/**
* Tests {@link SendFusionTablesUtils#getMapUrl(Track)} with null track.
*/
public void testGetMapUrl_null_track() {
assertEquals(null, SendFusionTablesUtils.getMapUrl(null));
}
/**
* Tests {@link SendFusionTablesUtils#getMapUrl(Track)} with null table id.
*/
public void testGetMapUrl_null_table_id() {
Track track = new Track();
TripStatistics stats = new TripStatistics();
stats.setBounds((int) 100.E6, (int) 10.E6, (int) 50.E6, (int) 5.E6);
track.setStatistics(stats);
track.setTableId(null);
assertEquals(null, SendFusionTablesUtils.getMapUrl(track));
}
/**
* Tests {@link SendFusionTablesUtils#getMapUrl(Track)} with null stats.
*/
public void testGetMapUrl_null_stats() {
Track track = new Track();
track.setStatistics(null);
track.setTableId("123");
assertEquals(null, SendFusionTablesUtils.getMapUrl(track));
}
/**
* Tests {@link SendFusionTablesUtils#getMapUrl(Track)} with a valid track.
*/
public void testGetMapUrl_valid_track() {
Track track = new Track();
TripStatistics stats = new TripStatistics();
stats.setBounds((int) 100.E6, (int) 10.E6, (int) 50.E6, (int) 5.E6);
track.setStatistics(stats);
track.setTableId("123");
assertEquals(
"https://www.google.com/fusiontables/embedviz?"
+ "viz=MAP&q=select+col0,+col1,+col2,+col3+from+123+&h=false&lat=7.500000&lng=75.000000"
+ "&z=15&t=1&l=col2", SendFusionTablesUtils.getMapUrl(track));
}
/**
* Tests (@link {@link SendFusionTablesUtils#formatSqlValues(String...)} with
* no value.
*/
public void testFormatSqlValues_no_value() {
assertEquals("()", SendFusionTablesUtils.formatSqlValues());
}
/**
* Tests (@link {@link SendFusionTablesUtils#formatSqlValues(String...)} with
* an empty string.
*/
public void testFormatSqlValues_empty_string() {
assertEquals("(\'\')", SendFusionTablesUtils.formatSqlValues(""));
}
/**
* Tests (@link {@link SendFusionTablesUtils#formatSqlValues(String...)} with
* one value.
*/
public void testFormatSqlValues_one_value() {
assertEquals("(\'first\')", SendFusionTablesUtils.formatSqlValues("first"));
}
/**
* Tests (@link {@link SendFusionTablesUtils#formatSqlValues(String...)} with
* two values.
*/
public void testFormatSqlValues_two_values() {
assertEquals(
"(\'first\',\'second\')", SendFusionTablesUtils.formatSqlValues("first", "second"));
}
/**
* Tests {@link SendFusionTablesUtils#escapeSqlString(String)} with a value
* containing several single quotes.
*/
public void testEscapeSqValuel() {
String value = "let's'";
assertEquals("let''s''", SendFusionTablesUtils.escapeSqlString(value));
}
/**
* Tests {@link SendFusionTablesUtils#getKmlPoint(Location)} with a null
* point.
*/
public void testGetKmlPoint_null_point() {
assertEquals(
"<Point><coordinates></coordinates></Point>", SendFusionTablesUtils.getKmlPoint(null));
}
/**
* Tests {@link SendFusionTablesUtils#getKmlPoint(Location)} with a valid
* point.
*/
public void testGetKmlPoint_valid_point() {
Location location = new Location("test");
location.setLongitude(10.1);
location.setLatitude(20.2);
location.setAltitude(30.3);
assertEquals("<Point><coordinates>10.1,20.2,30.3</coordinates></Point>",
SendFusionTablesUtils.getKmlPoint(location));
}
/**
* Tests {@link SendFusionTablesUtils#getKmlLineString(ArrayList)} with a null
* locations.
*/
public void testKmlLineString_null_locations() {
assertEquals("<LineString><coordinates></coordinates></LineString>",
SendFusionTablesUtils.getKmlLineString(null));
}
/**
* Tests {@link SendFusionTablesUtils#getKmlLineString(ArrayList)} with no
* location.
*/
public void testKmlLineString_no_location() {
ArrayList<Location> locations = new ArrayList<Location>();
assertEquals("<LineString><coordinates></coordinates></LineString>",
SendFusionTablesUtils.getKmlLineString(locations));
}
/**
* Tests {@link SendFusionTablesUtils#getKmlLineString(ArrayList)} with one
* location.
*/
public void testKmlLineString_one_location() {
ArrayList<Location> locations = new ArrayList<Location>();
Location location = new Location("test");
location.setLongitude(10.1);
location.setLatitude(20.2);
location.setAltitude(30.3);
locations.add(location);
assertEquals("<LineString><coordinates>10.1,20.2,30.3</coordinates></LineString>",
SendFusionTablesUtils.getKmlLineString(locations));
}
/**
* Tests {@link SendFusionTablesUtils#getKmlLineString(ArrayList)} with two
* locations.
*/
public void testKmlLineString_two_locations() {
ArrayList<Location> locations = new ArrayList<Location>();
Location location1 = new Location("test");
location1.setLongitude(10.1);
location1.setLatitude(20.2);
location1.setAltitude(30.3);
locations.add(location1);
Location location2 = new Location("test");
location2.setLongitude(1.1);
location2.setLatitude(2.2);
location2.removeAltitude();
locations.add(location2);
assertEquals("<LineString><coordinates>10.1,20.2,30.3 1.1,2.2</coordinates></LineString>",
SendFusionTablesUtils.getKmlLineString(locations));
}
/**
* Tests {@link SendFusionTablesUtils#appendLocation(Location, StringBuilder)}
* with no altitude.
*/
public void testAppendLocation_no_altitude() {
StringBuilder builder = new StringBuilder();
Location location = new Location("test");
location.setLongitude(10.1);
location.setLatitude(20.2);
location.removeAltitude();
SendFusionTablesUtils.appendLocation(location, builder);
assertEquals("10.1,20.2", builder.toString());
}
/**
* Tests {@link SendFusionTablesUtils#appendLocation(Location, StringBuilder)}
* with altitude.
*/
public void testAppendLocation_has_altitude() {
StringBuilder builder = new StringBuilder();
Location location = new Location("test");
location.setLongitude(10.1);
location.setLatitude(20.2);
location.setAltitude(30.3);
SendFusionTablesUtils.appendLocation(location, builder);
assertEquals("10.1,20.2,30.3", builder.toString());
}
/**
* Tests {@link SendFusionTablesUtils#getTableId(InputStream)} with a null
* inputstream.
*/
public void testGetTableId_null() {
assertEquals(null, SendFusionTablesUtils.getTableId(null));
}
/**
* Tests {@link SendFusionTablesUtils#getTableId(InputStream)} with an
* inputstream containing no data.
*/
public void testGetTableId_no_data() {
InputStream inputStream = new ByteArrayInputStream(new byte[0]);
assertEquals(null, SendFusionTablesUtils.getTableId(inputStream));
}
/**
* Tests {@link SendFusionTablesUtils#getTableId(InputStream)} with an empty
* inputstream.
*/
public void testGetTableId_empty() {
String string = "";
InputStream inputStream = new ByteArrayInputStream(string.getBytes());
assertEquals(null, SendFusionTablesUtils.getTableId(inputStream));
}
/**
* Tests {@link SendFusionTablesUtils#getTableId(InputStream)} with an one
* line inputstream.
*/
public void testGetTableId_one_line() {
String string = "tableid";
InputStream inputStream = new ByteArrayInputStream(string.getBytes());
assertEquals(null, SendFusionTablesUtils.getTableId(inputStream));
}
/**
* Tests {@link SendFusionTablesUtils#getTableId(InputStream)} with an
* inputstream not containing "tableid".
*/
public void testGetTableId_no_table_id() {
String string = "error\n123";
InputStream inputStream = new ByteArrayInputStream(string.getBytes());
assertEquals(null, SendFusionTablesUtils.getTableId(inputStream));
}
/**
* Tests {@link SendFusionTablesUtils#getTableId(InputStream)} with a valid
* inputstream.
*/
public void testGetTableId() {
String string = "tableid\n123";
InputStream inputStream = null;
inputStream = new ByteArrayInputStream(string.getBytes());
assertEquals("123", SendFusionTablesUtils.getTableId(inputStream));
}
}
@@ -0,0 +1,144 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.maps;
import com.google.android.apps.mytracks.io.gdata.maps.MapsMapMetadata;
import com.google.android.maps.mytracks.R;
import android.content.Intent;
import android.test.AndroidTestCase;
import android.widget.ArrayAdapter;
import java.util.ArrayList;
/**
* Tests the {@link ChooseMapActivity}.
*
* @author Youtao Liu
*/
public class ChooseMapActivityTest extends AndroidTestCase {
private static final String MAP_ID = "mapid";
private static final String MAP_TITLE = "title";
private static final String MAP_DESC = "desc";
private ArrayList<String> mapIds = new ArrayList<String>();
private ArrayList<MapsMapMetadata> mapDatas = new ArrayList<MapsMapMetadata>();
private boolean errorDialogShown = false;
private boolean progressDialogRemoved = false;
/**
* Creates a class to override some methods of {@link ChooseMapActivity} to
* makes it testable.
*
* @author youtaol
*/
public class ChooseMapActivityMock extends ChooseMapActivity {
/**
* By overriding this method, avoids to start next activity.
*/
@Override
public void startActivity(Intent intent) {}
/**
* By overriding this method, avoids to show an error dialog and set the
* show flag to true.
*/
@Override
public void showErrorDialog() {
errorDialogShown = true;
}
/**
* By overriding this method, avoids to show an error dialog and set the
* show flag to true.
*/
@Override
public void removeProgressDialog() {
progressDialogRemoved = true;
}
}
/**
* Tests the method
* {@link ChooseMapActivity#onAsyncTaskCompleted(boolean, ArrayList, ArrayList)}
* . An alert dialog should be shown when there is no map.
*/
public void testOnAsyncTaskCompleted_fail() {
ChooseMapActivityMock chooseMapActivityMock = new ChooseMapActivityMock();
errorDialogShown = false;
progressDialogRemoved = false;
chooseMapActivityMock.onAsyncTaskCompleted(false, null, null);
assertTrue(progressDialogRemoved);
assertTrue(errorDialogShown);
}
/**
* Tests the method
* {@link ChooseMapActivity#onAsyncTaskCompleted(boolean, ArrayList, ArrayList)}
* . Check the logic when there is only map.
*/
public void testOnAsyncTaskCompleted_success_oneMap() {
ChooseMapActivityMock chooseMapActivityMock = new ChooseMapActivityMock();
chooseMapActivityMock.arrayAdapter = new ArrayAdapter<ChooseMapActivity.ListItem>(getContext(),
R.layout.choose_map_item);
simulateMaps(1);
chooseMapActivityMock.onAsyncTaskCompleted(true, mapIds, mapDatas);
assertEquals(1, chooseMapActivityMock.arrayAdapter.getCount());
assertEquals(MAP_ID + "0", chooseMapActivityMock.arrayAdapter.getItem(0).getMapId());
assertEquals(MAP_TITLE + "0", chooseMapActivityMock.arrayAdapter.getItem(0).getMapData()
.getTitle());
assertEquals(MAP_DESC + "0", chooseMapActivityMock.arrayAdapter.getItem(0).getMapData()
.getDescription());
}
/**
* Tests the method
* {@link ChooseMapActivity#onAsyncTaskCompleted(boolean, ArrayList, ArrayList)}
* . Check the logic when there are 10 maps.
*/
public void testOnAsyncTaskCompleted_success_twoMaps() {
ChooseMapActivityMock chooseMapActivityMock = new ChooseMapActivityMock();
chooseMapActivityMock.arrayAdapter = new ArrayAdapter<ChooseMapActivity.ListItem>(getContext(),
R.layout.choose_map_item);
simulateMaps(10);
chooseMapActivityMock.onAsyncTaskCompleted(true, mapIds, mapDatas);
assertEquals(10, chooseMapActivityMock.arrayAdapter.getCount());
assertEquals(MAP_ID + "9", chooseMapActivityMock.arrayAdapter.getItem(9).getMapId());
assertEquals(MAP_TITLE + "9", chooseMapActivityMock.arrayAdapter.getItem(9).getMapData()
.getTitle());
assertEquals(MAP_DESC + "9", chooseMapActivityMock.arrayAdapter.getItem(9).getMapData()
.getDescription());
}
/**
* Simulates map data for the test.
*
* @param number of data should be simulated.
*/
private void simulateMaps(int number) {
mapIds = new ArrayList<String>();
mapDatas = new ArrayList<MapsMapMetadata>();
for (int i = 0; i < number; i++) {
mapIds.add(MAP_ID + i);
MapsMapMetadata metaData = new MapsMapMetadata();
metaData.setTitle(MAP_TITLE + i);
metaData.setDescription(MAP_DESC + i);
metaData.setSearchable(true);
mapDatas.add(metaData);
}
}
}
@@ -0,0 +1,199 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.maps;
import com.google.android.testing.mocking.AndroidMock;
import com.google.android.testing.mocking.UsesMocks;
import android.accounts.Account;
import android.test.AndroidTestCase;
import java.util.ArrayList;
/**
* Tests {@link ChooseMapAsyncTask}.
*
* @author Youtao Liu
*/
public class ChooseMapAsyncTaskTest extends AndroidTestCase {
private ChooseMapActivity chooseMapActivityMock;
private Account account;
private static final String ACCOUNT_NAME = "AccountName";
private static final String ACCOUNT_TYPE = "AccountType";
private boolean getMapsStatus = false;
public class ChooseMapAsyncTaskMock extends ChooseMapAsyncTask {
public ChooseMapAsyncTaskMock(ChooseMapActivity activity, Account account) {
super(activity, account);
}
/**
* Creates this method to override {@link ChooseMapAsyncTask#getMaps()}.
*
* @return mock the return value of getMaps().
*/
@Override
boolean getMaps() {
return getMapsStatus;
}
}
/**
* Tests {@link ChooseMapAsyncTask#setActivity(ChooseMapActivity)} when the
* task is completed. Makes sure it calls
* {@link ChooseMapActivity#onAsyncTaskCompleted(boolean, ArrayList, ArrayList)}
* .
*/
public void testSetActivity_completed() {
setup();
chooseMapActivityMock.onAsyncTaskCompleted(false, null, null);
AndroidMock.replay(chooseMapActivityMock);
ChooseMapAsyncTask chooseMapAsyncTask = new ChooseMapAsyncTask(chooseMapActivityMock, account);
chooseMapAsyncTask.setCompleted(true);
chooseMapAsyncTask.setActivity(chooseMapActivityMock);
AndroidMock.verify(chooseMapActivityMock);
}
/**
* Test {@link ChooseMapAsyncTask#setActivity(ChooseMapActivity)} when the
* task is not completed. Makes sure
* {@link ChooseMapActivity#onAsyncTaskCompleted(boolean, ArrayList, ArrayList)}
* is not invoked.
*/
public void testSetActivity_notCompleted() {
setup();
AndroidMock.replay(chooseMapActivityMock);
ChooseMapAsyncTask chooseMapAsyncTask = new ChooseMapAsyncTask(chooseMapActivityMock, account);
chooseMapAsyncTask.setCompleted(false);
chooseMapAsyncTask.setActivity(chooseMapActivityMock);
AndroidMock.verify(chooseMapActivityMock);
}
/**
* Tests {@link ChooseMapAsyncTask#setActivity(ChooseMapActivity)} when the
* activity is null. Makes sure
* {@link ChooseMapActivity#onAsyncTaskCompleted(boolean, ArrayList, ArrayList)}
* is not invoked.
*/
public void testSetActivity_nullActivity() {
setup();
AndroidMock.replay(chooseMapActivityMock);
ChooseMapAsyncTask chooseMapAsyncTask = new ChooseMapAsyncTask(chooseMapActivityMock, account);
chooseMapAsyncTask.setCompleted(true);
chooseMapAsyncTask.setActivity(null);
AndroidMock.verify(chooseMapActivityMock);
}
/**
* Tests the method {@link ChooseMapAsyncTask#onPostExecute(Boolean)} when the
* result is true. Makes sure
* {@link ChooseMapActivity#onAsyncTaskCompleted(boolean, ArrayList, ArrayList)}
* is invoked.
*/
public void testOnPostExecute_trueResult() {
setup();
chooseMapActivityMock.onAsyncTaskCompleted(true, null, null);
AndroidMock.replay(chooseMapActivityMock);
ChooseMapAsyncTask chooseMapAsyncTask = new ChooseMapAsyncTask(chooseMapActivityMock, account);
chooseMapAsyncTask.onPostExecute(true);
AndroidMock.verify(chooseMapActivityMock);
}
/**
* Tests the method {@link ChooseMapAsyncTask#onPostExecute(Boolean)} when the
* result is false. Makes sure
* {@link ChooseMapActivity#onAsyncTaskCompleted(boolean, ArrayList, ArrayList)}
* is invoked.
*/
public void testOnPostExecute_falseResult() {
setup();
chooseMapActivityMock.onAsyncTaskCompleted(false, null, null);
AndroidMock.replay(chooseMapActivityMock);
ChooseMapAsyncTask chooseMapAsyncTask = new ChooseMapAsyncTask(chooseMapActivityMock, account);
chooseMapAsyncTask.onPostExecute(false);
AndroidMock.verify(chooseMapActivityMock);
}
/**
* Tests the method {@link ChooseMapAsyncTask#retryUpload()}. Make sure can
* not retry again after have retried once and failed.
*/
public void testRetryUpload() throws Exception {
setup();
AndroidMock.replay(chooseMapActivityMock);
ChooseMapAsyncTaskMock chooseMapAsyncTaskTMock = new ChooseMapAsyncTaskMock(
chooseMapActivityMock, account);
chooseMapAsyncTaskTMock.setCanRetry(false);
getMapsStatus = true;
assertFalse(chooseMapAsyncTaskTMock.retryUpload());
AndroidMock.verify(chooseMapActivityMock);
}
/**
* Tests the method {@link ChooseMapAsyncTask#retryUpload()}. Make sure can
* retry after get maps failed and never retry before.
*/
public void testRetryUpload_retryOnce() throws Exception {
setup();
AndroidMock.replay(chooseMapActivityMock);
ChooseMapAsyncTaskMock chooseMapAsyncTaskTMock = new ChooseMapAsyncTaskMock(
chooseMapActivityMock, account);
chooseMapAsyncTaskTMock.setCanRetry(true);
getMapsStatus = false;
assertFalse(chooseMapAsyncTaskTMock.retryUpload());
// Can only retry once.
assertFalse(chooseMapAsyncTaskTMock.getCanRetry());
AndroidMock.verify(chooseMapActivityMock);
}
/**
* Tests the method {@link ChooseMapAsyncTask#retryUpload()}. Make sure will
* not retry after get maps successfully.
*/
public void testRetryUpload_successGetMaps() throws Exception {
setup();
AndroidMock.replay(chooseMapActivityMock);
ChooseMapAsyncTaskMock chooseMapAsyncTaskTMock = new ChooseMapAsyncTaskMock(
chooseMapActivityMock, account);
chooseMapAsyncTaskTMock.setCanRetry(true);
getMapsStatus = true;
assertTrue(chooseMapAsyncTaskTMock.retryUpload());
// Can only retry once.
assertFalse(chooseMapAsyncTaskTMock.getCanRetry());
AndroidMock.verify(chooseMapActivityMock);
}
/**
* Initials setup for test.
*/
void setup() {
setupChooseMapActivityMock();
account = new Account(ACCOUNT_NAME, ACCOUNT_TYPE);
}
/**
* Create a mock object of ChooseMapActivity.
*/
@UsesMocks(ChooseMapActivity.class)
private void setupChooseMapActivityMock() {
chooseMapActivityMock = AndroidMock.createMock(ChooseMapActivity.class);
// This is used in the constructor of ChooseMapAsyncTask.
AndroidMock.expect(chooseMapActivityMock.getApplicationContext()).andReturn(getContext()).anyTimes();
}
}
@@ -0,0 +1,90 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.maps;
import com.google.android.apps.mytracks.io.docs.SendDocsActivity;
import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity;
import android.test.AndroidTestCase;
/**
* Tests the {@link SendMapsActivity}.
*
* @author Youtao Liu
*/
public class SendMapsActivityTest extends AndroidTestCase {
private SendMapsActivity sendMapsActivity;
private SendRequest sendRequest;
@Override
protected void setUp() throws Exception {
super.setUp();
sendRequest = new SendRequest(1L, true, false, true);
sendMapsActivity = new SendMapsActivity();
}
/**
* Tests the method
* {@link SendMapsActivity#getNextClass(SendRequest, boolean)}. Sets the flags
* of "sendFusionTables","sendDocs" and "cancel" to true, true and false.
*/
public void testGetNextClass_notCancelSendFusionTables() {
sendRequest.setSendFusionTables(true);
sendRequest.setSendDocs(true);
Class<?> next = sendMapsActivity.getNextClass(sendRequest, false);
assertEquals(SendFusionTablesActivity.class, next);
}
/**
* Tests the method
* {@link SendMapsActivity#getNextClass(SendRequest, boolean)}. Sets the flags
* of "sendFusionTables","sendDocs" and "cancel" to false, true and false.
*/
public void testGetNextClass_notCancelSendDocs() {
sendRequest.setSendFusionTables(false);
sendRequest.setSendDocs(true);
Class<?> next = sendMapsActivity.getNextClass(sendRequest, false);
assertEquals(SendDocsActivity.class, next);
}
/**
* Tests the method
* {@link SendMapsActivity#getNextClass(SendRequest, boolean)}. Sets the flags
* of "sendFusionTables","sendDocs" and "cancel" to false, false and false.
*/
public void testGetNextClass_notCancelNotSend() {
sendRequest.setSendFusionTables(false);
sendRequest.setSendDocs(false);
Class<?> next = sendMapsActivity.getNextClass(sendRequest, false);
assertEquals(UploadResultActivity.class, next);
}
/**
* Tests the method
* {@link SendMapsActivity#getNextClass(SendRequest, boolean)}. Sets the flags
* of "sendFusionTables","sendDocs" and "cancel" to true, true and true.
*/
public void testGetNextClass_cancelSendDocs() {
sendRequest.setSendFusionTables(true);
sendRequest.setSendDocs(true);
Class<?> next = sendMapsActivity.getNextClass(sendRequest, true);
assertEquals(UploadResultActivity.class, next);
}
}
@@ -0,0 +1,356 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.maps;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.TrackStubUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.gdata.maps.MapsGDataConverter;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.testing.mocking.AndroidMock;
import com.google.android.testing.mocking.UsesMocks;
import android.accounts.Account;
import android.database.Cursor;
import android.location.Location;
import android.test.AndroidTestCase;
import java.util.List;
import org.xmlpull.v1.XmlPullParserException;
/**
* Tests {@link SendMapsAsyncTask}.
*
* @author Youtao Liu
*/
public class SendMapsAsyncTaskTest extends AndroidTestCase {
private static final long TRACK_ID = 1;
private static final String MAP_ID = "MapID_1";
// Records the run times of {@link SendMapsAsyncTaskMock#uploadMarker(String,
// String, String, Location)}
private int uploadMarkerCounter = 0;
// Records the run times of {@link
// SendMapsAsyncTaskMock#prepareAndUploadPoints(Track, List<Location>,
// boolean)}
private int prepareAndUploadPointsCounter = 0;
private SendMapsActivity sendMapsActivityMock;
private MyTracksProviderUtils myTracksProviderUtilsMock;
private SendRequest sendRequest;
private class SendMapsAsyncTaskMock extends SendMapsAsyncTask {
private boolean[] uploadMarkerResult = { false, false };
private boolean prepareAndUploadPointsResult = false;
private SendMapsAsyncTaskMock(SendMapsActivity activity, long trackId, Account account,
String chooseMapId, MyTracksProviderUtils myTracksProviderUtils) {
super(activity, trackId, account, chooseMapId, myTracksProviderUtils);
}
@Override
boolean uploadMarker(String title, String description, String iconUrl, Location location) {
int runTimes = uploadMarkerCounter++;
return uploadMarkerResult[runTimes];
}
@Override
boolean prepareAndUploadPoints(Track track, List<Location> locations, boolean lastBatch) {
prepareAndUploadPointsCounter++;
return prepareAndUploadPointsResult;
}
}
@Override
@UsesMocks({ SendMapsActivity.class, MyTracksProviderUtils.class })
protected void setUp() throws Exception {
super.setUp();
uploadMarkerCounter = 0;
prepareAndUploadPointsCounter = 0;
sendMapsActivityMock = AndroidMock.createMock(SendMapsActivity.class);
myTracksProviderUtilsMock = AndroidMock.createMock(MyTracksProviderUtils.class);
sendRequest = new SendRequest(TRACK_ID, false, true, false);
AndroidMock.expect(sendMapsActivityMock.getApplicationContext()).andReturn(getContext());
}
/**
* Tests the method {@link SendMapsAsyncTask#saveResult()}and makes sure the
* track is updated.
*/
public void testSaveResult() {
Track track = TrackStubUtils.createTrack(1);
track.setMapId(null);
AndroidMock.expect(myTracksProviderUtilsMock.getTrack(TRACK_ID)).andReturn(track);
myTracksProviderUtilsMock.updateTrack(track);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock);
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), sendRequest.getMapId(),
myTracksProviderUtilsMock);
sendMapsAsyncTask.saveResult();
assertEquals(sendRequest.getMapId(), track.getMapId());
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock);
}
/**
* Tests {@link SendMapsAsyncTask#fetchSendMapId(Track)} when chooseMapId is
* null and makes sure it returns false.
*/
public void testFetchSendMapId_nullMapID() {
Track track = TrackStubUtils.createTrack(1);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock);
// Makes chooseMapId to null.
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), null, myTracksProviderUtilsMock);
// Returns false for an exception would be thrown.
assertFalse(sendMapsAsyncTask.fetchSendMapId(track));
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#fetchSendMapId(Track)} when
* chooseMapId is not null. And makes sure it returns false.
*/
public void testFetchSendMapId_notNullMapID() {
Track track = TrackStubUtils.createTrack(1);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock);
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), MAP_ID, myTracksProviderUtilsMock);
assertTrue(sendMapsAsyncTask.fetchSendMapId(track));
assertEquals(MAP_ID, sendMapsAsyncTask.getMapId());
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadAllTrackPoints(Track)} when
* cursor is null. And makes sure it returns false.
*/
public void testUploadAllTrackPoints_nullCursor() {
Track track = TrackStubUtils.createTrack(1);
AndroidMock.expect(myTracksProviderUtilsMock.getLocationsCursor(TRACK_ID, 0, -1, false))
.andReturn(null);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock);
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), MAP_ID, myTracksProviderUtilsMock);
assertFalse(sendMapsAsyncTask.uploadAllTrackPoints(track));
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadAllTrackPoints(Track)} when
* uploads the first marker is failed.
*/
@UsesMocks(Cursor.class)
public void testUploadAllTrackPoints_uploadFirstMarkerFailed() {
Track track = TrackStubUtils.createTrack(1);
Cursor cursorMock = AndroidMock.createMock(Cursor.class);
AndroidMock.expect(cursorMock.getCount()).andReturn(2);
AndroidMock.expect(cursorMock.moveToPosition(0)).andReturn(true);
cursorMock.close();
AndroidMock.expect(myTracksProviderUtilsMock.createLocation(cursorMock)).andReturn(
new Location("1"));
AndroidMock.expect(myTracksProviderUtilsMock.getLocationsCursor(TRACK_ID, 0, -1, false))
.andReturn(cursorMock);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
SendMapsAsyncTaskMock sendMapsAsyncTask = new SendMapsAsyncTaskMock(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), MAP_ID, myTracksProviderUtilsMock);
sendMapsAsyncTask.uploadMarkerResult[0] = false;
assertFalse(sendMapsAsyncTask.uploadAllTrackPoints(track));
assertEquals(1, uploadMarkerCounter);
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadAllTrackPoints(Track)} when
* uploads the two markers is successful but failed when
* prepareAndUploadPoints.
*/
@UsesMocks(Cursor.class)
public void testUploadAllTrackPoints_prepareAndUploadPointsFailed() {
Track track = TrackStubUtils.createTrack(1);
Cursor cursorMock = AndroidMock.createMock(Cursor.class);
AndroidMock.expect(cursorMock.getCount()).andReturn(2);
AndroidMock.expect(cursorMock.moveToPosition(0)).andReturn(true);
AndroidMock.expect(cursorMock.moveToPosition(1)).andReturn(true);
cursorMock.close();
AndroidMock.expect(myTracksProviderUtilsMock.createLocation(cursorMock))
.andReturn(new Location("1")).times(2);
AndroidMock.expect(myTracksProviderUtilsMock.getLocationsCursor(TRACK_ID, 0, -1, false))
.andReturn(cursorMock);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
SendMapsAsyncTaskMock sendMapsAsyncTask = new SendMapsAsyncTaskMock(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), MAP_ID, myTracksProviderUtilsMock);
// For will be failed when run prepareAndUploadPoints, it no require to
// set uploadMarkerResult[1].
sendMapsAsyncTask.uploadMarkerResult[0] = true;
sendMapsAsyncTask.prepareAndUploadPointsResult = false;
assertFalse(sendMapsAsyncTask.uploadAllTrackPoints(track));
assertEquals(1, uploadMarkerCounter);
assertEquals(1, prepareAndUploadPointsCounter);
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadAllTrackPoints(Track)} when
* uploads the last marker is failed.
*/
@UsesMocks(Cursor.class)
public void testUploadAllTrackPoints_uploadLastMarkerFailed() {
Track track = TrackStubUtils.createTrack(1);
Cursor cursorMock = AndroidMock.createMock(Cursor.class);
AndroidMock.expect(cursorMock.getCount()).andReturn(2);
AndroidMock.expect(cursorMock.moveToPosition(0)).andReturn(true);
AndroidMock.expect(cursorMock.moveToPosition(1)).andReturn(true);
cursorMock.close();
AndroidMock.expect(myTracksProviderUtilsMock.createLocation(cursorMock))
.andReturn(new Location("1")).times(2);
AndroidMock.expect(myTracksProviderUtilsMock.getLocationsCursor(TRACK_ID, 0, -1, false))
.andReturn(cursorMock);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
SendMapsAsyncTaskMock sendMapsAsyncTask = new SendMapsAsyncTaskMock(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), MAP_ID, myTracksProviderUtilsMock);
sendMapsAsyncTask.uploadMarkerResult[0] = true;
sendMapsAsyncTask.uploadMarkerResult[1] = false;
sendMapsAsyncTask.prepareAndUploadPointsResult = true;
assertFalse(sendMapsAsyncTask.uploadAllTrackPoints(track));
assertEquals(2, uploadMarkerCounter);
assertEquals(1, prepareAndUploadPointsCounter);
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadAllTrackPoints(Track)} when
* return true.
*/
@UsesMocks(Cursor.class)
public void testUploadAllTrackPoints_success() {
Track track = TrackStubUtils.createTrack(1);
Cursor cursorMock = AndroidMock.createMock(Cursor.class);
AndroidMock.expect(cursorMock.getCount()).andReturn(2);
AndroidMock.expect(cursorMock.moveToPosition(0)).andReturn(true);
AndroidMock.expect(cursorMock.moveToPosition(1)).andReturn(true);
cursorMock.close();
AndroidMock.expect(myTracksProviderUtilsMock.createLocation(cursorMock))
.andReturn(new Location("1")).times(2);
AndroidMock.expect(myTracksProviderUtilsMock.getLocationsCursor(TRACK_ID, 0, -1, false))
.andReturn(cursorMock);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
SendMapsAsyncTaskMock sendMapsAsyncTask = new SendMapsAsyncTaskMock(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), MAP_ID, myTracksProviderUtilsMock);
sendMapsAsyncTask.uploadMarkerResult[0] = true;
sendMapsAsyncTask.uploadMarkerResult[1] = true;
sendMapsAsyncTask.prepareAndUploadPointsResult = true;
assertTrue(sendMapsAsyncTask.uploadAllTrackPoints(track));
assertEquals(2, uploadMarkerCounter);
assertEquals(1, prepareAndUploadPointsCounter);
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadWaypoints()} when cursor is
* null.
*/
@UsesMocks(Cursor.class)
public void testUploadWaypoints_nullCursor() {
AndroidMock.expect(
myTracksProviderUtilsMock.getWaypointsCursor(TRACK_ID, 0,
Constants.MAX_LOADED_WAYPOINTS_POINTS)).andReturn(null);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock);
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), MAP_ID, myTracksProviderUtilsMock);
assertTrue(sendMapsAsyncTask.uploadWaypoints());
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadWaypoints()} when there is
* only one point.
*/
@UsesMocks(Cursor.class)
public void testUploadWaypoints_onePoint() {
Cursor cursorMock = AndroidMock.createMock(Cursor.class);
AndroidMock.expect(cursorMock.moveToFirst()).andReturn(true);
// Only one point, so next is null.
AndroidMock.expect(cursorMock.moveToNext()).andReturn(false);
cursorMock.close();
AndroidMock.expect(
myTracksProviderUtilsMock.getWaypointsCursor(TRACK_ID, 0,
Constants.MAX_LOADED_WAYPOINTS_POINTS)).andReturn(cursorMock);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), MAP_ID, myTracksProviderUtilsMock);
assertTrue(sendMapsAsyncTask.uploadWaypoints());
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#uploadWaypoints()}. Makes sure a cursor is created and
* a way point is created with such cursor.
*
* @throws XmlPullParserException
*/
@UsesMocks(Cursor.class)
public void testUploadWaypoints() throws XmlPullParserException {
Cursor cursorMock = AndroidMock.createMock(Cursor.class);
MapsGDataConverter mapsGDataConverterMock = new MapsGDataConverter();
AndroidMock.expect(cursorMock.moveToFirst()).andReturn(true);
AndroidMock.expect(cursorMock.moveToNext()).andReturn(true);
cursorMock.close();
AndroidMock.expect(
myTracksProviderUtilsMock.getWaypointsCursor(TRACK_ID, 0,
Constants.MAX_LOADED_WAYPOINTS_POINTS)).andReturn(cursorMock);
Waypoint waypoint = new Waypoint();
waypoint.setLocation(TrackStubUtils.createMyTracksLocation());
AndroidMock.expect(myTracksProviderUtilsMock.createWaypoint(cursorMock)).andReturn(waypoint)
.times(1);
AndroidMock.replay(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
SendMapsAsyncTask sendMapsAsyncTask = new SendMapsAsyncTask(sendMapsActivityMock,
sendRequest.getTrackId(), sendRequest.getAccount(), MAP_ID, myTracksProviderUtilsMock);
sendMapsAsyncTask.setMapsGDataConverter(mapsGDataConverterMock);
// Would be failed for there is no source for uploading.
assertFalse(sendMapsAsyncTask.uploadWaypoints());
AndroidMock.verify(sendMapsActivityMock, myTracksProviderUtilsMock, cursorMock);
}
/**
* Tests the method {@link SendMapsAsyncTask#getPercentage(int, int)}.
*/
public void testCountPercentage() {
assertEquals(SendMapsAsyncTask.PROGRESS_UPLOAD_DATA_MIN, SendMapsAsyncTask.getPercentage(0, 5));
assertEquals(SendMapsAsyncTask.PROGRESS_UPLOAD_DATA_MAX,
SendMapsAsyncTask.getPercentage(50, 50));
assertEquals(
(int) ((double) 5
/ 11
* (SendMapsAsyncTask.PROGRESS_UPLOAD_DATA_MAX - SendMapsAsyncTask.PROGRESS_UPLOAD_DATA_MIN) + SendMapsAsyncTask.PROGRESS_UPLOAD_DATA_MIN),
SendMapsAsyncTask.getPercentage(5, 11));
}
}
@@ -0,0 +1,179 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.maps;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.gdata.maps.MapsFeature;
import com.google.android.maps.GeoPoint;
import android.location.Location;
import java.util.ArrayList;
import junit.framework.TestCase;
/**
* Tests {@link SendMapsUtils}.
*
* @author Jimmy Shih
*/
public class SendMapsUtilsTest extends TestCase {
/**
* Tests {@link SendMapsUtils#getMapUrl(Track)} with null track.
*/
public void testGetMapUrl_null_track() {
assertEquals(null, SendMapsUtils.getMapUrl(null));
}
/**
* Tests {@link SendMapsUtils#getMapUrl(Track)} with null map id.
*/
public void testGetMapUrl_null_map_id() {
Track track = new Track();
track.setMapId(null);
assertEquals(null, SendMapsUtils.getMapUrl(track));
}
/**
* Tests {@link SendMapsUtils#getMapUrl(Track)} with a valid track.
*/
public void testGetMapUrl_valid_track() {
Track track = new Track();
track.setMapId("123");
assertEquals("https://maps.google.com/maps/ms?msa=0&msid=123", SendMapsUtils.getMapUrl(track));
}
/**
* Test {@link SendMapsUtils#buildMapsMarkerFeature(String, String, String,
* GeoPoint)} with a title.
*/
public void testBuildMapsMarkerFeature_with_title() {
MapsFeature mapFeature = SendMapsUtils.buildMapsMarkerFeature(
"name", "this\nmap\ndescription", "url", new GeoPoint(123, 456));
assertEquals(MapsFeature.MARKER, mapFeature.getType());
assertNotNull(mapFeature.getAndroidId());
assertEquals("name", mapFeature.getTitle());
assertEquals("this<br>map<br>description", mapFeature.getDescription());
assertEquals("url", mapFeature.getIconUrl());
assertEquals(123, mapFeature.getPoint(0).getLatitudeE6());
assertEquals(456, mapFeature.getPoint(0).getLongitudeE6());
}
/**
* Test {@link SendMapsUtils#buildMapsMarkerFeature(String, String, String,
* GeoPoint)} with an empty title.
*/
public void testBuildMapsMarkerFeature_empty_title() {
MapsFeature mapFeature = SendMapsUtils.buildMapsMarkerFeature(
"", "description", "url", new GeoPoint(123, 456));
assertEquals(MapsFeature.MARKER, mapFeature.getType());
assertNotNull(mapFeature.getAndroidId());
assertEquals("-", mapFeature.getTitle());
assertEquals("description", mapFeature.getDescription());
assertEquals("url", mapFeature.getIconUrl());
assertEquals(123, mapFeature.getPoint(0).getLatitudeE6());
assertEquals(456, mapFeature.getPoint(0).getLongitudeE6());
}
/**
* Test {@link SendMapsUtils#buildMapsMarkerFeature(String, String, String,
* GeoPoint)} with a null title.
*/
public void testBuildMapsMarkerFeature_null_title() {
MapsFeature mapFeature = SendMapsUtils.buildMapsMarkerFeature(
null, "description", "url", new GeoPoint(123, 456));
assertEquals(MapsFeature.MARKER, mapFeature.getType());
assertNotNull(mapFeature.getAndroidId());
assertEquals("-", mapFeature.getTitle());
assertEquals("description", mapFeature.getDescription());
assertEquals("url", mapFeature.getIconUrl());
assertEquals(123, mapFeature.getPoint(0).getLatitudeE6());
assertEquals(456, mapFeature.getPoint(0).getLongitudeE6());
}
/**
* Test {@link SendMapsUtils#buildMapsLineFeature(String, ArrayList)} with a
* title.
*/
public void testBuildMapsLineFeature_with_title() {
ArrayList<Location> locations = new ArrayList<Location>();
Location location = new Location("test");
location.setLatitude(50);
location.setLongitude(100);
locations.add(location);
MapsFeature mapFeature = SendMapsUtils.buildMapsLineFeature("name", locations);
assertEquals(MapsFeature.LINE, mapFeature.getType());
assertNotNull(mapFeature.getAndroidId());
assertEquals("name", mapFeature.getTitle());
assertEquals(0x80FF0000, mapFeature.getColor());
assertEquals(50000000, mapFeature.getPoint(0).getLatitudeE6());
assertEquals(100000000, mapFeature.getPoint(0).getLongitudeE6());
}
/**
* Test {@link SendMapsUtils#buildMapsLineFeature(String, ArrayList)} with an
* empty title.
*/
public void testBuildMapsLineFeature_empty_title() {
ArrayList<Location> locations = new ArrayList<Location>();
Location location = new Location("test");
location.setLatitude(50);
location.setLongitude(100);
locations.add(location);
MapsFeature mapFeature = SendMapsUtils.buildMapsLineFeature("", locations);
assertEquals(MapsFeature.LINE, mapFeature.getType());
assertNotNull(mapFeature.getAndroidId());
assertEquals("-", mapFeature.getTitle());
assertEquals(0x80FF0000, mapFeature.getColor());
assertEquals(50000000, mapFeature.getPoint(0).getLatitudeE6());
assertEquals(100000000, mapFeature.getPoint(0).getLongitudeE6());
}
/**
* Test {@link SendMapsUtils#buildMapsLineFeature(String, ArrayList)} with a
* null title.
*/
public void testBuildMapsLineFeature_null_title() {
ArrayList<Location> locations = new ArrayList<Location>();
Location location = new Location("test");
location.setLatitude(50);
location.setLongitude(100);
locations.add(location);
MapsFeature mapFeature = SendMapsUtils.buildMapsLineFeature(null, locations);
assertEquals(MapsFeature.LINE, mapFeature.getType());
assertNotNull(mapFeature.getAndroidId());
assertEquals("-", mapFeature.getTitle());
assertEquals(0x80FF0000, mapFeature.getColor());
assertEquals(50000000, mapFeature.getPoint(0).getLatitudeE6());
assertEquals(100000000, mapFeature.getPoint(0).getLongitudeE6());
}
/**
* Test {@link SendMapsUtils#getGeoPoint(Location)}.
*/
public void testGeoPoint() {
Location location = new Location("test");
location.setLatitude(50);
location.setLongitude(100);
GeoPoint geoPoint = SendMapsUtils.getGeoPoint(location);
assertEquals(50000000, geoPoint.getLatitudeE6());
assertEquals(100000000, geoPoint.getLongitudeE6());
}
}
@@ -0,0 +1,333 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.sendtogoogle;
import android.accounts.Account;
import android.os.Parcel;
import android.os.Parcelable;
import android.test.AndroidTestCase;
/**
* Tests the {@link SendRequest}.
*
* @author Youtao Liu
*/
public class SendRequestTest extends AndroidTestCase {
private SendRequest sendRequest;
final static private String ACCOUNTNAME = "testAccount1";
final static private String ACCOUNTYPE = "testType1";
final static private String MAPID = "mapId1";
@Override
protected void setUp() throws Exception {
super.setUp();
sendRequest = new SendRequest(1, true, true, true);
}
/**
* Tests the method {@link SendRequest#getTrackId()}. The value should be set
* to 1 when it is initialed in setup method.
*/
public void testGetTrackId() {
assertEquals(1, sendRequest.getTrackId());
}
/**
* Tests the method {@link SendRequest#isShowMaps()}. The value should be set
* to true when it is initialed in setup method.
*/
public void testIsShowMaps() {
assertEquals(true, sendRequest.isShowMaps());
}
/**
* Tests the method {@link SendRequest#isShowFusionTables()}. The value should
* be set to true when it is initialed in setup method.
*/
public void testIsShowFusionTables() {
assertEquals(true, sendRequest.isShowFusionTables());
}
/**
* Tests the method {@link SendRequest#isShowDocs()}. The value should be set
* to true when it is initialed in setup method.
*/
public void testIsShowDocs() {
assertEquals(true, sendRequest.isShowDocs());
}
public void testIsShowAll() {
assertEquals(true, sendRequest.isShowAll());
sendRequest = new SendRequest(1, false, true, true);
assertEquals(false, sendRequest.isShowAll());
sendRequest = new SendRequest(1, true, false, true);
assertEquals(false, sendRequest.isShowAll());
sendRequest = new SendRequest(1, true, true, false);
assertEquals(false, sendRequest.isShowAll());
sendRequest = new SendRequest(1, false, true, false);
assertEquals(false, sendRequest.isShowAll());
sendRequest = new SendRequest(1, false, false, false);
assertEquals(false, sendRequest.isShowAll());
}
public void testIsSendMaps() {
assertEquals(false, sendRequest.isSendMaps());
sendRequest.setSendMaps(true);
assertEquals(true, sendRequest.isSendMaps());
}
public void testIsSendFusionTables() {
assertEquals(false, sendRequest.isSendFusionTables());
sendRequest.setSendFusionTables(true);
assertEquals(true, sendRequest.isSendFusionTables());
}
/**
* Tests the method {@link SendRequest#isSendDocs()}. The value should be set
* to false which is its default value when it is initialed in setup method.
*/
public void testIsSendDocs() {
assertEquals(false, sendRequest.isSendDocs());
sendRequest.setSendDocs(true);
assertEquals(true, sendRequest.isSendDocs());
}
/**
* Tests the method {@link SendRequest#isNewMap()}. The value should be set to
* false which is its default value when it is initialed in setup method.
*/
public void testIsNewMap() {
assertEquals(false, sendRequest.isNewMap());
sendRequest.setNewMap(true);
assertEquals(true, sendRequest.isNewMap());
}
/**
* Tests the method {@link SendRequest#getAccount()}. The value should be set
* to null which is its default value when it is initialed in setup method.
*/
public void testGetAccount() {
assertEquals(null, sendRequest.getAccount());
Account account = new Account(ACCOUNTNAME, ACCOUNTYPE);
sendRequest.setAccount(account);
assertEquals(account, sendRequest.getAccount());
}
/**
* Tests the method {@link SendRequest#getMapId()}. The value should be set to
* null which is its default value when it is initialed in setup method.
*/
public void testGetMapId() {
assertEquals(null, sendRequest.getMapId());
sendRequest.setMapId("1");
assertEquals("1", "1");
}
/**
* Tests the method {@link SendRequest#isMapsSuccess()}. The value should be
* set to false which is its default value when it is initialed in setup
* method.
*/
public void testIsMapsSuccess() {
assertEquals(false, sendRequest.isMapsSuccess());
sendRequest.setMapsSuccess(true);
assertEquals(true, sendRequest.isMapsSuccess());
}
/**
* Tests the method {@link SendRequest#isFusionTablesSuccess()}. The value
* should be set to false which is its default value when it is initialed in
* setup method.
*/
public void testIsFusionTablesSuccess() {
assertEquals(false, sendRequest.isFusionTablesSuccess());
sendRequest.setFusionTablesSuccess(true);
assertEquals(true, sendRequest.isFusionTablesSuccess());
}
/**
* Tests the method {@link SendRequest#isDocsSuccess()}. The value should be
* set to false which is its default value when it is initialed in setup
* method.
*/
public void testIsDocsSuccess() {
assertEquals(false, sendRequest.isDocsSuccess());
sendRequest.setDocsSuccess(true);
assertEquals(true, sendRequest.isDocsSuccess());
}
/**
* Tests SendRequest.CREATOR.createFromParcel when all values are true.
*/
public void testCreateFromParcel_true() {
Parcel sourceParcel = Parcel.obtain();
sourceParcel.setDataPosition(0);
sourceParcel.writeLong(2);
sourceParcel.writeByte((byte) 1);
sourceParcel.writeByte((byte) 1);
sourceParcel.writeByte((byte) 1);
sourceParcel.writeByte((byte) 1);
sourceParcel.writeByte((byte) 1);
sourceParcel.writeByte((byte) 1);
sourceParcel.writeByte((byte) 1);
Account account = new Account(ACCOUNTNAME, ACCOUNTYPE);
sourceParcel.writeParcelable(account, 0);
sourceParcel.writeString(MAPID);
sourceParcel.writeByte((byte) 1);
sourceParcel.writeByte((byte) 1);
sourceParcel.writeByte((byte) 1);
sourceParcel.setDataPosition(0);
sendRequest = SendRequest.CREATOR.createFromParcel(sourceParcel);
assertEquals(2, sendRequest.getTrackId());
assertEquals(true, sendRequest.isShowMaps());
assertEquals(true, sendRequest.isShowFusionTables());
assertEquals(true, sendRequest.isShowDocs());
assertEquals(true, sendRequest.isSendMaps());
assertEquals(true, sendRequest.isSendFusionTables());
assertEquals(true, sendRequest.isSendDocs());
assertEquals(true, sendRequest.isNewMap());
assertEquals(account, sendRequest.getAccount());
assertEquals(MAPID, sendRequest.getMapId());
assertEquals(true, sendRequest.isMapsSuccess());
assertEquals(true, sendRequest.isFusionTablesSuccess());
assertEquals(true, sendRequest.isDocsSuccess());
}
/**
* Tests SendRequest.CREATOR.createFromParcel when all values are false.
*/
public void testCreateFromParcel_false() {
Parcel sourceParcel = Parcel.obtain();
sourceParcel.setDataPosition(0);
sourceParcel.writeLong(4);
sourceParcel.writeByte((byte) 0);
sourceParcel.writeByte((byte) 0);
sourceParcel.writeByte((byte) 0);
sourceParcel.writeByte((byte) 0);
sourceParcel.writeByte((byte) 0);
sourceParcel.writeByte((byte) 0);
sourceParcel.writeByte((byte) 0);
Account account = new Account(ACCOUNTNAME, ACCOUNTYPE);
sourceParcel.writeParcelable(account, 0);
sourceParcel.writeString(MAPID);
sourceParcel.writeByte((byte) 0);
sourceParcel.writeByte((byte) 0);
sourceParcel.writeByte((byte) 0);
sourceParcel.setDataPosition(0);
sendRequest = SendRequest.CREATOR.createFromParcel(sourceParcel);
assertEquals(4, sendRequest.getTrackId());
assertEquals(false, sendRequest.isShowMaps());
assertEquals(false, sendRequest.isShowFusionTables());
assertEquals(false, sendRequest.isShowDocs());
assertEquals(false, sendRequest.isSendMaps());
assertEquals(false, sendRequest.isSendFusionTables());
assertEquals(false, sendRequest.isSendDocs());
assertEquals(false, sendRequest.isNewMap());
assertEquals(account, sendRequest.getAccount());
assertEquals(MAPID, sendRequest.getMapId());
assertEquals(false, sendRequest.isMapsSuccess());
assertEquals(false, sendRequest.isFusionTablesSuccess());
assertEquals(false, sendRequest.isDocsSuccess());
}
/**
* Tests {@link SendRequest#writeToParcel(Parcel, int)} when all input values
* are true or affirmative.
*/
public void testWriteToParcel_allTrue() {
sendRequest = new SendRequest(1, false, false, false);
Parcel parcelWrite1st = Parcel.obtain();
parcelWrite1st.setDataPosition(0);
sendRequest.writeToParcel(parcelWrite1st, 1);
parcelWrite1st.setDataPosition(0);
long trackId = parcelWrite1st.readLong();
boolean showMaps = parcelWrite1st.readByte() == 1;
boolean showFusionTables = parcelWrite1st.readByte() == 1;
boolean showDocs = parcelWrite1st.readByte() == 1;
boolean sendMaps = parcelWrite1st.readByte() == 1;
boolean sendFusionTables = parcelWrite1st.readByte() == 1;
boolean sendDocs = parcelWrite1st.readByte() == 1;
boolean newMap = parcelWrite1st.readByte() == 1;
Parcelable account = parcelWrite1st.readParcelable(null);
String mapId = parcelWrite1st.readString();
boolean mapsSuccess = parcelWrite1st.readByte() == 1;
boolean fusionTablesSuccess = parcelWrite1st.readByte() == 1;
boolean docsSuccess = parcelWrite1st.readByte() == 1;
assertEquals(1, trackId);
assertEquals(false, showMaps);
assertEquals(false, showFusionTables);
assertEquals(false, showDocs);
assertEquals(false, sendMaps);
assertEquals(false, sendFusionTables);
assertEquals(false, sendDocs);
assertEquals(false, newMap);
assertEquals(null, account);
assertEquals(null, mapId);
assertEquals(false, mapsSuccess);
assertEquals(false, fusionTablesSuccess);
assertEquals(false, docsSuccess);
}
/**
* Tests {@link SendRequest#writeToParcel(Parcel, int)} when all input values
* are false or negative.
*/
public void testWriteToParcel_allFalse() {
sendRequest = new SendRequest(4, true, true, true);
sendRequest.setSendMaps(true);
sendRequest.setSendFusionTables(true);
sendRequest.setSendDocs(true);
sendRequest.setNewMap(true);
Account accountNew = new Account(ACCOUNTNAME + "2", ACCOUNTYPE + "2");
sendRequest.setAccount(accountNew);
sendRequest.setMapId(MAPID);
sendRequest.setMapsSuccess(true);
sendRequest.setFusionTablesSuccess(true);
sendRequest.setDocsSuccess(true);
Parcel parcelWrite2nd = Parcel.obtain();
parcelWrite2nd.setDataPosition(0);
sendRequest.writeToParcel(parcelWrite2nd, 1);
parcelWrite2nd.setDataPosition(0);
long trackId = parcelWrite2nd.readLong();
boolean showMaps = parcelWrite2nd.readByte() == 1;
boolean showFusionTables = parcelWrite2nd.readByte() == 1;
boolean showDocs = parcelWrite2nd.readByte() == 1;
boolean sendMaps = parcelWrite2nd.readByte() == 1;
boolean sendFusionTables = parcelWrite2nd.readByte() == 1;
boolean sendDocs = parcelWrite2nd.readByte() == 1;
boolean newMap = parcelWrite2nd.readByte() == 1;
Parcelable account = parcelWrite2nd.readParcelable(null);
String mapId = parcelWrite2nd.readString();
boolean mapsSuccess = parcelWrite2nd.readByte() == 1;
boolean fusionTablesSuccess = parcelWrite2nd.readByte() == 1;
boolean docsSuccess = parcelWrite2nd.readByte() == 1;
assertEquals(4, trackId);
assertEquals(true, showMaps);
assertEquals(true, showFusionTables);
assertEquals(true, showDocs);
assertEquals(true, sendMaps);
assertEquals(true, sendFusionTables);
assertEquals(true, sendDocs);
assertEquals(true, newMap);
assertEquals(accountNew, account);
assertEquals(MAPID, mapId);
assertEquals(true, mapsSuccess);
assertEquals(true, fusionTablesSuccess);
assertEquals(true, docsSuccess);
}
}
@@ -0,0 +1,140 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.sendtogoogle;
/**
* Tests the {@link SendToGoogleUtils}.
*
* @author Youtao Liu
*/
import com.google.android.apps.mytracks.TrackStubUtils;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Track;
import android.location.Location;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
public class SendToGoogleUtilsTest extends TestCase {
private final static long TRACK_ID = 1L;
private final static String TRACK_CATEGORY = "trackCategory";
private final static String TRACK_NAME = "trackName";
private final static double DIFFERENCE = 0.02;
private final static double INVALID_LATITUDE = 91;
/**
* Tests the method
* {@link SendToGoogleUtils#prepareTrackSegment(Track, java.util.ArrayList)}
* when there is only one location in a segment.
*/
public void testPrepareTrackSegment_onlyOneLocation() {
Track trackStub = TrackStubUtils.createTrack(1);
assertFalse(SendToGoogleUtils.prepareTrackSegment(trackStub, null));
}
/**
* Tests the method
* {@link SendToGoogleUtils#prepareTrackSegment(Track, ArrayList)} when there
* is no stop time.
*/
public void testPrepareTrackSegment_noStopTime() {
Track trackStub = TrackStubUtils.createTrack(2);
assertEquals(-1L, trackStub.getStatistics().getStopTime());
ArrayList<Track> tracksArray = new ArrayList<Track>();
assertTrue(SendToGoogleUtils.prepareTrackSegment(trackStub, tracksArray));
assertEquals(trackStub, tracksArray.get(0));
// The stop time should be the time of last location
assertEquals(trackStub.getLocations().get(1).getTime(), trackStub.getStatistics().getStopTime());
}
/**
* Tests the method
* {@link SendToGoogleUtils#prepareTrackSegment(Track, java.util.ArrayList)}
* when there is stop time.
*/
public void testPrepareTrackSegment_hasStopTime() {
Track trackStub = TrackStubUtils.createTrack(2);
// Gives a margin to make sure the this time will be not same with the last
// location in the track.
long stopTime = System.currentTimeMillis() + 1000;
trackStub.getStatistics().setStopTime(stopTime);
ArrayList<Track> tracksArray = new ArrayList<Track>();
SendToGoogleUtils.prepareTrackSegment(trackStub, tracksArray);
assertEquals(trackStub, tracksArray.get(0));
assertEquals(stopTime, trackStub.getStatistics().getStopTime());
}
/**
* Tests the method
* {@link SendToGoogleUtils#prepareLocations(Track, java.util.List)} .
*/
public void testPrepareLocations() {
Track trackStub = TrackStubUtils.createTrack(2);
trackStub.setId(TRACK_ID);
trackStub.setName(TRACK_NAME);
trackStub.setCategory(TRACK_CATEGORY);
List<Location> locationsArray = new ArrayList<Location>();
// Adds 100 location to List.
for (int i = 0; i < 100; i++) {
// Use this variable as a flag to make all points in the track can be kept
// after run the LocationUtils#decimate(Track, double) with
// Ramer–Douglas–Peucker algorithm.
double latitude = TrackStubUtils.INITIAL_LATITUDE;
if (i % 2 == 0) {
latitude -= DIFFERENCE * (i % 10);
}
// Inserts 9 points which have wrong latitude, so would have 10 segments.
if (i % 10 == 0 && i > 0) {
MyTracksLocation location = TrackStubUtils.createMyTracksLocation();
location.setLatitude(INVALID_LATITUDE);
locationsArray.add(location);
} else {
locationsArray.add(TrackStubUtils.createMyTracksLocation(latitude,
TrackStubUtils.INITIAL_LONGITUDE + DIFFERENCE * (i % 10),
TrackStubUtils.INITIAL_ALTITUDE + DIFFERENCE * (i % 10)));
}
}
ArrayList<Track> result = SendToGoogleUtils.prepareLocations(trackStub, locationsArray);
assertEquals(10, result.size());
// Checks all segments.
for (int i = 0; i < 10; i++) {
Track segmentOne = result.get(i);
assertEquals(TRACK_ID, segmentOne.getId());
assertEquals(TRACK_NAME, segmentOne.getName());
assertEquals(TRACK_CATEGORY, segmentOne.getCategory());
}
// Checks all locations in the first segment.
for (int j = 0; j < 9; j++) {
double latitude = TrackStubUtils.INITIAL_LATITUDE;
if (j % 2 == 0) {
latitude -= DIFFERENCE * (j % 10);
}
Location oneLocation = result.get(0).getLocations().get(j);
assertEquals(TrackStubUtils.createMyTracksLocation().getAltitude() + DIFFERENCE * (j % 10),
oneLocation.getAltitude());
assertEquals(latitude, oneLocation.getLatitude());
assertEquals(TrackStubUtils.createMyTracksLocation().getLongitude() + DIFFERENCE * (j % 10),
oneLocation.getLongitude());
}
}
}
@@ -0,0 +1,169 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.sendtogoogle;
import com.google.android.maps.mytracks.R;
import com.jayway.android.robotium.solo.Solo;
import android.app.Instrumentation;
import android.content.Intent;
import android.test.ActivityInstrumentationTestCase2;
import android.view.View;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashSet;
/**
* Tests the {@link UploadResultActivity}.
*
* @author Youtao Liu
*/
public class UploadResultActivityTest extends
ActivityInstrumentationTestCase2<UploadResultActivity> {
private Instrumentation instrumentation;
private UploadResultActivity uploadResultActivity;
private Solo solo;
@Override
protected void setUp() throws Exception {
super.setUp();
instrumentation = getInstrumentation();
solo = new Solo(instrumentation);
}
/**
* This method is necessary for ActivityInstrumentationTestCase2.
*/
public UploadResultActivityTest() {
super(UploadResultActivity.class);
}
/**
* Checks the display of dialog when send to all and all sends are successful.
*/
public void testAllSuccess() {
initialActivity(true, true, true, true, true, true);
HashSet<String> stringHashSet = new HashSet<String>();
ArrayList<View> view = solo.getViews();
for (View oneView : view) {
if (oneView instanceof TextView && oneView.isShown()) {
stringHashSet.add((String) ((TextView) oneView).getText());
}
}
assertTrue(stringHashSet.contains(uploadResultActivity
.getString(R.string.generic_success_title)));
assertTrue(stringHashSet.contains(uploadResultActivity.getString(R.string.send_google_maps)));
assertTrue(stringHashSet.contains(uploadResultActivity
.getString(R.string.send_google_fusion_tables)));
assertTrue(stringHashSet.contains(uploadResultActivity.getString(R.string.send_google_docs)));
assertTrue(stringHashSet.contains(uploadResultActivity
.getString(R.string.send_google_success_footer)));
assertFalse(stringHashSet
.contains(uploadResultActivity.getString(R.string.generic_error_title)));
assertFalse(stringHashSet.contains(uploadResultActivity.getString(R.string.send_google_error)));
}
/**
* Checks the display of dialog when send to all and all sends are failed.
*/
public void testAllFailed() {
// Send all kinds but all failed.
initialActivity(true, true, true, false, false, false);
HashSet<String> stringHashSet = new HashSet<String>();
ArrayList<View> view = solo.getViews();
for (View oneView : view) {
if (oneView instanceof TextView && oneView.isShown()) {
stringHashSet.add((String) ((TextView) oneView).getText());
}
}
assertTrue(stringHashSet.contains((Object) uploadResultActivity
.getString(R.string.generic_error_title)));
assertTrue(stringHashSet.contains(uploadResultActivity.getString(R.string.send_google_maps)));
assertTrue(stringHashSet.contains(uploadResultActivity
.getString(R.string.send_google_fusion_tables)));
assertTrue(stringHashSet.contains(uploadResultActivity.getString(R.string.send_google_docs)));
assertTrue(stringHashSet.contains(uploadResultActivity.getString(R.string.send_google_error)));
assertFalse(stringHashSet.contains(uploadResultActivity
.getString(R.string.generic_success_title)));
assertFalse(stringHashSet.contains(uploadResultActivity
.getString(R.string.send_google_success_footer)));
}
/**
* Checks the display of dialog when match following items:
* <ul>
* <li>Only send to Maps and Docs.</li>
* <li>Send to Maps successful.</li>
* <li>Send to Docs failed.</li>
* </ul>
*/
public void testPartialSuccess() {
initialActivity(true, false, true, true, false, false);
HashSet<String> stringHashSet = new HashSet<String>();
ArrayList<View> view = solo.getViews();
for (View oneView : view) {
if (oneView instanceof TextView && oneView.isShown()) {
stringHashSet.add((String) ((TextView) oneView).getText());
}
}
assertTrue(stringHashSet.contains(uploadResultActivity.getString(R.string.generic_error_title)));
assertTrue(stringHashSet.contains(uploadResultActivity.getString(R.string.send_google_maps)));
assertTrue(stringHashSet.contains(uploadResultActivity.getString(R.string.send_google_docs)));
assertTrue(stringHashSet.contains(uploadResultActivity.getString(R.string.send_google_error)));
assertFalse(stringHashSet.contains(uploadResultActivity
.getString(R.string.send_google_fusion_tables)));
assertFalse(stringHashSet.contains(uploadResultActivity
.getString(R.string.generic_success_title)));
assertFalse(stringHashSet.contains(uploadResultActivity
.getString(R.string.send_google_success_footer)));
}
/**
* Initial a {@link SendRequest} and then initials a activity to be tested.
*
* @param isSendMaps
* @param isSendFusionTables
* @param isSendDocs
* @param isMapsSuccess
* @param isFusionTablesSuccess
* @param isDocsSuccess
*/
private void initialActivity(boolean isSendMaps, boolean isSendFusionTables, boolean isSendDocs,
boolean isMapsSuccess, boolean isFusionTablesSuccess, boolean isDocsSuccess) {
Intent intent = new Intent();
SendRequest sendRequest = new SendRequest(1L, true, true, true);
sendRequest.setSendMaps(isSendMaps);
sendRequest.setSendFusionTables(isSendFusionTables);
sendRequest.setSendDocs(isSendDocs);
sendRequest.setMapsSuccess(isMapsSuccess);
sendRequest.setFusionTablesSuccess(isFusionTablesSuccess);
sendRequest.setDocsSuccess(isDocsSuccess);
intent.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
setActivityIntent(intent);
uploadResultActivity = this.getActivity();
}
}
@@ -0,0 +1,275 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.sendtogoogle;
import com.google.android.apps.mytracks.Constants;
import com.google.android.maps.mytracks.R;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.test.ActivityInstrumentationTestCase2;
import android.widget.CheckBox;
import android.widget.RadioButton;
/**
* Tests the {@link UploadServiceChooserActivity}.
*
* @author Youtao Liu
*/
public class UploadServiceChooserActivityTest extends
ActivityInstrumentationTestCase2<UploadServiceChooserActivity> {
private Instrumentation instrumentation;
private UploadServiceChooserActivity uploadServiceChooserActivity;
public UploadServiceChooserActivityTest() {
super(UploadServiceChooserActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
instrumentation = getInstrumentation();
}
/**
* Tests the logic to display all options.
*/
public void testOnCreateDialog_displayAll() {
// Initials activity to display all send items.
initialActivity(true, true, true);
instrumentation.waitForIdleSync();
assertTrue(getMapsCheckBox().isShown());
assertTrue(getFusionTablesCheckBox().isShown());
assertTrue(getDocsCheckBox().isShown());
// Clicks to disable all send items.
uploadServiceChooserActivity.runOnUiThread(new Runnable() {
public void run() {
if (getMapsCheckBox().isChecked()) {
getMapsCheckBox().performClick();
}
if (getFusionTablesCheckBox().isChecked()) {
getFusionTablesCheckBox().performClick();
}
if (getDocsCheckBox().isChecked()) {
getDocsCheckBox().performClick();
}
}
});
instrumentation.waitForIdleSync();
assertTrue(getMapsCheckBox().isShown());
assertTrue(getFusionTablesCheckBox().isShown());
assertTrue(getDocsCheckBox().isShown());
assertFalse(getNewMapRadioButton().isShown());
assertFalse(getExistingMapRadioButton().isShown());
}
/**
* Tests the logic to display only the "Send to Google Maps" option.
*/
public void testOnCreateDialog_displayOne() {
// Initials activity to display all send items.
initialActivity(true, false, false);
instrumentation.waitForIdleSync();
assertTrue(getMapsCheckBox().isShown());
// Clicks to enable this items.
uploadServiceChooserActivity.runOnUiThread(new Runnable() {
public void run() {
if (!getMapsCheckBox().isChecked()) {
getMapsCheckBox().performClick();
}
}
});
instrumentation.waitForIdleSync();
assertTrue(getMapsCheckBox().isShown());
assertTrue(getNewMapRadioButton().isShown());
assertTrue(getExistingMapRadioButton().isShown());
}
/**
* Tests the logic to display no option.
*/
public void testOnCreateDialog_displayNone() {
initialActivity(false, false, false);
assertFalse(getMapsCheckBox().isShown());
assertFalse(getFusionTablesCheckBox().isShown());
assertFalse(getDocsCheckBox().isShown());
}
/**
* Tests the logic to initial state of check box to unchecked. This test cover
* code in method {@link UploadServiceChooserActivity#onCreateDialog(int)},
* {@link UploadServiceChooserActivity#initState()}.
*/
public void testOnCreateDialog_initStateUnchecked() {
initialActivity(true, true, true);
// Initial all values to false in SharedPreferences.
SharedPreferences prefs = uploadServiceChooserActivity.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.send_to_maps_key), false);
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.send_to_fusion_tables_key),
false);
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.send_to_docs_key), false);
editor.commit();
uploadServiceChooserActivity.runOnUiThread(new Runnable() {
public void run() {
uploadServiceChooserActivity.initState();
}
});
instrumentation.waitForIdleSync();
assertFalse(getMapsCheckBox().isChecked());
assertFalse(getFusionTablesCheckBox().isChecked());
assertFalse(getDocsCheckBox().isChecked());
}
/**
* Tests the logic to initial state of check box to checked. This test cover
* code in method {@link UploadServiceChooserActivity#onCreateDialog(int)},
* {@link UploadServiceChooserActivity#initState()}.
*/
public void testOnCreateDialog_initStateChecked() {
initialActivity(true, true, true);
// Initial all values to true in SharedPreferences.
SharedPreferences prefs = uploadServiceChooserActivity.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.send_to_maps_key), true);
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.pick_existing_map_key), true);
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.send_to_fusion_tables_key),
true);
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.send_to_docs_key), true);
editor.commit();
uploadServiceChooserActivity.runOnUiThread(new Runnable() {
public void run() {
uploadServiceChooserActivity.initState();
}
});
instrumentation.waitForIdleSync();
assertTrue(getMapsCheckBox().isChecked());
assertTrue(getFusionTablesCheckBox().isChecked());
assertTrue(getDocsCheckBox().isChecked());
assertTrue(getExistingMapRadioButton().isChecked());
assertFalse(getNewMapRadioButton().isChecked());
}
/**
* Tests the logic of saveState when click send button. This test cover code
* in method {@link UploadServiceChooserActivity#initState()} and
* {@link UploadServiceChooserActivity#saveState()},
*/
public void testOnCreateDialog_saveState() {
initialActivity(true, true, true);
// Initial all values to true in SharedPreferences.
SharedPreferences prefs = uploadServiceChooserActivity.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.send_to_maps_key), true);
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.send_to_fusion_tables_key),
true);
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.send_to_docs_key), true);
editor.commit();
uploadServiceChooserActivity.runOnUiThread(new Runnable() {
public void run() {
uploadServiceChooserActivity.initState();
}
});
instrumentation.waitForIdleSync();
uploadServiceChooserActivity.saveState();
// All values in SharedPreferences must be changed.
assertTrue(prefs.getBoolean(uploadServiceChooserActivity.getString(R.string.send_to_maps_key),
false));
assertTrue(prefs.getBoolean(uploadServiceChooserActivity.getString(R.string.send_to_maps_key),
false));
assertTrue(prefs.getBoolean(uploadServiceChooserActivity.getString(R.string.send_to_maps_key),
false));
}
/**
* Tests the logic of startNextActivity when click send button. This test
* cover code in method {@link UploadServiceChooserActivity#initState()} and
* {@link UploadServiceChooserActivity#startNextActivity()}.
*/
public void testOnCreateDialog_startNextActivity() {
initialActivity(true, true, true);
// Initial all values to true or false in SharedPreferences.
SharedPreferences prefs = uploadServiceChooserActivity.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.send_to_maps_key), true);
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.send_to_docs_key), true);
editor.putBoolean(uploadServiceChooserActivity.getString(R.string.send_to_fusion_tables_key),
false);
editor.commit();
uploadServiceChooserActivity.runOnUiThread(new Runnable() {
public void run() {
uploadServiceChooserActivity.initState();
}
});
instrumentation.waitForIdleSync();
uploadServiceChooserActivity.startNextActivity();
// All values in SendRequest must be same as set above.
assertTrue(uploadServiceChooserActivity.getSendRequest().isSendMaps());
assertTrue(uploadServiceChooserActivity.getSendRequest().isSendDocs());
assertFalse(uploadServiceChooserActivity.getSendRequest().isSendFusionTables());
}
/**
* Initials a activity to be tested.
*
* @param showMaps
* @param showFusionTables
* @param showDocs
*/
private void initialActivity(boolean showMaps, boolean showFusionTables, boolean showDocs) {
Intent intent = new Intent();
intent.putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(1L, showMaps, showFusionTables,
showDocs));
setActivityIntent(intent);
uploadServiceChooserActivity = this.getActivity();
}
private CheckBox getMapsCheckBox() {
return (CheckBox) uploadServiceChooserActivity.getAlertDialog().findViewById(R.id.send_google_maps);
}
private CheckBox getFusionTablesCheckBox() {
return (CheckBox) uploadServiceChooserActivity.getAlertDialog().findViewById(
R.id.send_google_fusion_tables);
}
private CheckBox getDocsCheckBox() {
return (CheckBox) uploadServiceChooserActivity.getAlertDialog().findViewById(R.id.send_google_docs);
}
private RadioButton getNewMapRadioButton() {
return (RadioButton) uploadServiceChooserActivity.getAlertDialog().findViewById(
R.id.send_google_new_map);
}
private RadioButton getExistingMapRadioButton() {
return (RadioButton) uploadServiceChooserActivity.getAlertDialog().findViewById(
R.id.send_google_existing_map);
}
}
@@ -0,0 +1,180 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.maps;
import com.google.android.apps.mytracks.Constants;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.test.AndroidTestCase;
/**
* Tests for the {@link DynamicSpeedTrackPathDescriptor}.
*
* @author Youtao Liu
*/
public class DynamicSpeedTrackPathDescriptorTest extends AndroidTestCase {
private Context context;
private SharedPreferences sharedPreferences;
private Editor sharedPreferencesEditor;
@Override
protected void setUp() throws Exception {
super.setUp();
context = getContext();
sharedPreferences = context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
sharedPreferencesEditor = sharedPreferences.edit();
}
/**
* Tests the method {@link DynamicSpeedTrackPathDescriptor#getSpeedMargin()}
* with zero, normal and illegal value.
*/
public void testGetSpeedMargin() {
String[] actuals = { "0", "50", "99", "" };
// The default value of speedMargin is 25.
int[] expectations = { 0, 50, 99, 25 };
// Test
for (int i = 0; i < expectations.length; i++) {
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_dynamic_speed_variation_key), actuals[i]);
sharedPreferencesEditor.commit();
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
assertEquals(expectations[i],
dynamicSpeedTrackPathDescriptor.getSpeedMargin(sharedPreferences));
}
}
/**
* Tests {@link
* DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences,
* String)} when the key is null.
*/
public void testOnSharedPreferenceChanged_nullKey() {
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
int speedMargin = dynamicSpeedTrackPathDescriptor.getSpeedMargin(sharedPreferences);
// Change value in shared preferences.
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_dynamic_speed_variation_key),
Integer.toString(speedMargin + 2));
sharedPreferencesEditor.commit();
dynamicSpeedTrackPathDescriptor.onSharedPreferenceChanged(sharedPreferences, null);
assertEquals(speedMargin, dynamicSpeedTrackPathDescriptor.getSpeedMargin());
}
/**
* Tests {@link
* DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences,
* String)} when the key is not null, and not trackColorModeDynamicVariation.
*/
public void testOnSharedPreferenceChanged_otherKey() {
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
int speedMargin = dynamicSpeedTrackPathDescriptor.getSpeedMargin(sharedPreferences);
// Change value in shared preferences.
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_dynamic_speed_variation_key),
Integer.toString(speedMargin + 2));
sharedPreferencesEditor.commit();
dynamicSpeedTrackPathDescriptor.onSharedPreferenceChanged(sharedPreferences, "anyKey");
assertEquals(speedMargin, dynamicSpeedTrackPathDescriptor.getSpeedMargin());
}
/**
* Tests {@link
* DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences,
* String)} when the key is trackColorModeDynamicVariation.
*/
public void testOnSharedPreferenceChanged_trackColorModeDynamicVariationKey() {
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
int speedMargin = dynamicSpeedTrackPathDescriptor.getSpeedMargin(sharedPreferences);
// Change value in shared preferences.
sharedPreferencesEditor.putString(
"trackColorModeDynamicVariation",
Integer.toString(speedMargin + 2));
sharedPreferencesEditor.commit();
dynamicSpeedTrackPathDescriptor.onSharedPreferenceChanged(sharedPreferences,
"trackColorModeDynamicVariation");
assertEquals(speedMargin + 2, dynamicSpeedTrackPathDescriptor.getSpeedMargin());
}
/**
* Tests {@link
* DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences,
* String)} when the values of speedMargin is "".
*/
public void testOnSharedPreferenceChanged_emptyValue() {
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
// Change value in shared preferences
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_dynamic_speed_variation_key), "");
sharedPreferencesEditor.commit();
dynamicSpeedTrackPathDescriptor.onSharedPreferenceChanged(sharedPreferences,
context.getString(R.string.track_color_mode_dynamic_speed_variation_key));
// The default value of speedMargin is 25.
assertEquals(25, dynamicSpeedTrackPathDescriptor.getSpeedMargin());
}
/**
* Tests {@link DynamicSpeedTrackPathDescriptor#needsRedraw()} by wrong track
* id.
*/
public void testNeedsRedraw_WrongTrackId() {
long trackId = -1;
sharedPreferencesEditor.putLong(context.getString(R.string.selected_track_key), trackId);
sharedPreferencesEditor.commit();
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
assertEquals(false, dynamicSpeedTrackPathDescriptor.needsRedraw());
}
/**
* Tests {@link DynamicSpeedTrackPathDescriptor#needsRedraw()} by different
* averageMovingSpeed.
*/
public void testIsDiffereceSignificant() {
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
double[] averageMovingSpeeds = { 0, 30, 30, 30 };
double[] newAverageMovingSpeed = { 20, 30,
// Difference is less than CRITICAL_DIFFERENCE_PERCENTAGE
30 * (1 + (DynamicSpeedTrackPathDescriptor.CRITICAL_DIFFERENCE_PERCENTAGE / 100) / 2),
// Difference is more than CRITICAL_DIFFERENCE_PERCENTAGE
30 * (1 + (DynamicSpeedTrackPathDescriptor.CRITICAL_DIFFERENCE_PERCENTAGE / 100.00) * 2) };
boolean[] expectedValues = { true, false, false, true };
double[] expectedAverageMovingSpeed = { 20, 30, 30,
30 * (1 + (DynamicSpeedTrackPathDescriptor.CRITICAL_DIFFERENCE_PERCENTAGE / 100.00) * 2) };
// Test
for (int i = 0; i < newAverageMovingSpeed.length; i++) {
dynamicSpeedTrackPathDescriptor.setAverageMovingSpeed(averageMovingSpeeds[i]);
assertEquals(expectedValues[i], dynamicSpeedTrackPathDescriptor.isDifferenceSignificant(
averageMovingSpeeds[i], newAverageMovingSpeed[i]));
assertEquals(expectedAverageMovingSpeed[i],
dynamicSpeedTrackPathDescriptor.getAverageMovingSpeed());
}
}
}
@@ -0,0 +1,187 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.maps;
import com.google.android.apps.mytracks.Constants;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.test.AndroidTestCase;
/**
* Tests for the {@link DynamicSpeedTrackPathDescriptor}.
*
* @author Youtao Liu
*/
public class FixedSpeedTrackPathDescriptorTest extends AndroidTestCase {
private Context context;
private SharedPreferences sharedPreferences;
private Editor sharedPreferencesEditor;
private int slowDefault;
private int normalDefault;
@Override
protected void setUp() throws Exception {
super.setUp();
context = getContext();
sharedPreferences = context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
sharedPreferencesEditor = sharedPreferences.edit();
// Get the default value
slowDefault = 9;
normalDefault = 15;
}
/**
* Tests the initialization of slowSpeed and normalSpeed in {@link
* DynamicSpeedTrackPathDescriptor#DynamicSpeedTrackPathDescriptor(Context)}.
*/
public void testConstructor() {
String[] slowSpeedsInShPre = { "0", "1", "99", "" };
int[] slowSpeedExpectations = { 0, 1, 99, slowDefault };
String[] normalSpeedsInShPre = { "0", "1", "99", "" };
int[] normalSpeedExpectations = { 0, 1, 99, normalDefault };
for (int i = 0; i < slowSpeedsInShPre.length; i++) {
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_fixed_speed_slow_key), slowSpeedsInShPre[i]);
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_fixed_speed_medium_key),
normalSpeedsInShPre[i]);
sharedPreferencesEditor.commit();
FixedSpeedTrackPathDescriptor fixedSpeedTrackPathDescriptor = new FixedSpeedTrackPathDescriptor(
context);
assertEquals(slowSpeedExpectations[i], fixedSpeedTrackPathDescriptor.getSlowSpeed());
assertEquals(normalSpeedExpectations[i], fixedSpeedTrackPathDescriptor.getNormalSpeed());
}
}
/**
* Tests {@link
* DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences,
* String)} when the key is null.
*/
public void testOnSharedPreferenceChanged_null_key() {
FixedSpeedTrackPathDescriptor fixedSpeedTrackPathDescriptor = new FixedSpeedTrackPathDescriptor(
context);
int slowSpeed = fixedSpeedTrackPathDescriptor.getSlowSpeed();
int normalSpeed = fixedSpeedTrackPathDescriptor.getNormalSpeed();
// Change value in shared preferences
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_fixed_speed_slow_key),
Integer.toString(slowSpeed + 2));
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_fixed_speed_medium_key),
Integer.toString(normalSpeed + 2));
sharedPreferencesEditor.commit();
fixedSpeedTrackPathDescriptor.onSharedPreferenceChanged(sharedPreferences, null);
assertEquals(slowSpeed, fixedSpeedTrackPathDescriptor.getSlowSpeed());
assertEquals(normalSpeed, fixedSpeedTrackPathDescriptor.getNormalSpeed());
}
/**
* Tests {@link
* DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences,
* String)} when the key is not null, and not slowSpeed and not normalSpeed.
*/
public void testOnSharedPreferenceChanged_other_key() {
FixedSpeedTrackPathDescriptor fixedSpeedTrackPathDescriptor = new FixedSpeedTrackPathDescriptor(
context);
int slowSpeed = fixedSpeedTrackPathDescriptor.getSlowSpeed();
int normalSpeed = fixedSpeedTrackPathDescriptor.getNormalSpeed();
// Change value in shared preferences
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_fixed_speed_slow_key),
Integer.toString(slowSpeed + 2));
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_fixed_speed_medium_key),
Integer.toString(normalSpeed + 2));
sharedPreferencesEditor.commit();
fixedSpeedTrackPathDescriptor.onSharedPreferenceChanged(sharedPreferences, "anyKey");
assertEquals(slowSpeed, fixedSpeedTrackPathDescriptor.getSlowSpeed());
assertEquals(normalSpeed, fixedSpeedTrackPathDescriptor.getNormalSpeed());
}
/**
* Tests {@link
* DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences,
* String)} when the key is slowSpeed.
*/
public void testOnSharedPreferenceChanged_slowSpeedKey() {
FixedSpeedTrackPathDescriptor fixedSpeedTrackPathDescriptor = new FixedSpeedTrackPathDescriptor(
context);
int slowSpeed = fixedSpeedTrackPathDescriptor.getSlowSpeed();
int normalSpeed = fixedSpeedTrackPathDescriptor.getNormalSpeed();
// Change value in shared preferences
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_fixed_speed_slow_key),
Integer.toString(slowSpeed + 2));
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_fixed_speed_medium_key),
Integer.toString(normalSpeed + 2));
sharedPreferencesEditor.commit();
fixedSpeedTrackPathDescriptor.onSharedPreferenceChanged(sharedPreferences,
context.getString(R.string.track_color_mode_fixed_speed_slow_key));
assertEquals(slowSpeed + 2, fixedSpeedTrackPathDescriptor.getSlowSpeed());
assertEquals(normalSpeed + 2, fixedSpeedTrackPathDescriptor.getNormalSpeed());
}
/**
* Tests {@link
* DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences,
* String)} when the key is normalSpeed.
*/
public void testOnSharedPreferenceChanged_normalSpeedKey() {
FixedSpeedTrackPathDescriptor fixedSpeedTrackPathDescriptor = new FixedSpeedTrackPathDescriptor(
context);
int slowSpeed = fixedSpeedTrackPathDescriptor.getSlowSpeed();
int normalSpeed = fixedSpeedTrackPathDescriptor.getNormalSpeed();
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_fixed_speed_slow_key),
Integer.toString(slowSpeed + 4));
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_fixed_speed_medium_key),
Integer.toString(normalSpeed + 4));
sharedPreferencesEditor.commit();
fixedSpeedTrackPathDescriptor.onSharedPreferenceChanged(sharedPreferences,
context.getString(R.string.track_color_mode_fixed_speed_medium_key));
assertEquals(slowSpeed + 4, fixedSpeedTrackPathDescriptor.getSlowSpeed());
assertEquals(normalSpeed + 4, fixedSpeedTrackPathDescriptor.getNormalSpeed());
}
/**
* Tests {@link
* DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences,
* String)} when the values of slowSpeed and normalSpeed in SharedPreference
* is "". In such situation, the default value should get returned.
*/
public void testOnSharedPreferenceChanged_emptyValue() {
FixedSpeedTrackPathDescriptor fixedSpeedTrackPathDescriptor = new FixedSpeedTrackPathDescriptor(
context);
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_fixed_speed_slow_key), "");
sharedPreferencesEditor.putString(
context.getString(R.string.track_color_mode_fixed_speed_medium_key), "");
sharedPreferencesEditor.commit();
fixedSpeedTrackPathDescriptor.onSharedPreferenceChanged(sharedPreferences,
context.getString(R.string.track_color_mode_fixed_speed_medium_key));
assertEquals(slowDefault, fixedSpeedTrackPathDescriptor.getSlowSpeed());
assertEquals(normalDefault, fixedSpeedTrackPathDescriptor.getNormalSpeed());
}
}
@@ -0,0 +1,52 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.maps;
import android.location.Location;
/**
* Tests for the MyTracks track path descriptors and painters.
*
* @author Vangelis S.
*/
public class TrackPathDescriptorDynamicSpeedTest extends TrackPathPainterTestCase {
public void testDynamicSpeedTrackPathDescriptor() throws Exception {
Location location = new Location("gps");
location.setLatitude(10);
for (int i = 0; i < 100; ++i) {
location = new Location("gps");
location.setLatitude(20 + i / 2);
location.setLongitude(150 - i);
myTracksOverlay.addLocation(location);
}
TrackPathPainter painter = new DynamicSpeedTrackPathPainter(
getContext(), new DynamicSpeedTrackPathDescriptor(getContext()));
myTracksOverlay.setTrackPathPainter(painter);
int startLocationIdx = 0;
Boolean alwaysVisible = true;
assertNotNull(painter);
painter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, alwaysVisible,
myTracksOverlay.getPoints());
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath());
painter.drawTrack(canvas);
}
}
@@ -0,0 +1,52 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.maps;
import android.location.Location;
/**
* Tests for the MyTracks track path descriptors and painters.
*
* @author Vangelis S.
*/
public class TrackPathDescriptorFixedSpeedTest extends TrackPathPainterTestCase {
public void testFixedSpeedTrackPathDescriptor() throws Exception {
Location location = new Location("gps");
location.setLatitude(10);
for (int i = 0; i < 100; ++i) {
location = new Location("gps");
location.setLatitude(20 + i / 2);
location.setLongitude(150 - i);
myTracksOverlay.addLocation(location);
}
TrackPathPainter painter = new DynamicSpeedTrackPathPainter(
getContext(), new FixedSpeedTrackPathDescriptor(getContext()));
myTracksOverlay.setTrackPathPainter(painter);
int startLocationIdx = 0;
Boolean alwaysVisible = true;
assertNotNull(painter);
painter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, alwaysVisible,
myTracksOverlay.getPoints());
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath());
painter.drawTrack(canvas);
}
}
@@ -0,0 +1,78 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.maps;
import com.google.android.apps.mytracks.Constants;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.location.Location;
/**
* Tests for the MyTracks track path painter factory.
*
* @author Vangelis S.
*/
public class TrackPathPainterFactoryTest extends TrackPathPainterTestCase {
public void testTrackPathPainterFactory() throws Exception {
Location location = new Location("gps");
location.setLatitude(10);
for (int i = 0; i < 100; ++i) {
location = new Location("gps");
location.setLatitude(20 + i / 2);
location.setLongitude(150 - i);
myTracksOverlay.addLocation(location);
}
Context context = getContext();
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (prefs == null) {
return;
}
testTrackPathPainterFactorySpecific(context, prefs, R.string.display_track_color_value_none,
SingleColorTrackPathPainter.class);
testTrackPathPainterFactorySpecific(context, prefs, R.string.display_track_color_value_fixed,
DynamicSpeedTrackPathPainter.class);
testTrackPathPainterFactorySpecific(context, prefs, R.string.display_track_color_value_dynamic,
DynamicSpeedTrackPathPainter.class);
}
private <T> void testTrackPathPainterFactorySpecific(Context context, SharedPreferences prefs,
int track_color_mode, Class <?> c) {
prefs.edit().putString(context.getString(R.string.track_color_mode_key),
context.getString(track_color_mode)).apply();
int startLocationIdx = 0;
Boolean alwaysVisible = true;
TrackPathPainter painter = TrackPathPainterFactory.getTrackPathPainter(context);
myTracksOverlay.setTrackPathPainter(painter);
assertNotNull(painter);
assertTrue(c.isInstance(painter));
painter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, alwaysVisible,
myTracksOverlay.getPoints());
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath());
painter.drawTrack(canvas);
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.maps;
import android.location.Location;
/**
* Tests for the MyTracks track path descriptors and painters.
*
* @author Vangelis S.
*/
public class TrackPathPainterSingleColorTest extends TrackPathPainterTestCase {
public void testSimpeColorTrackPathPainter() throws Exception {
Location location = new Location("gps");
location.setLatitude(10);
for (int i = 0; i < 100; ++i) {
location = new Location("gps");
location.setLatitude(20 + i / 2);
location.setLongitude(150 - i);
myTracksOverlay.addLocation(location);
}
TrackPathPainter painter = new SingleColorTrackPathPainter(getContext());
myTracksOverlay.setTrackPathPainter(painter);
int startLocationIdx = 0;
Boolean alwaysVisible = true;
assertNotNull(painter);
painter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, alwaysVisible,
myTracksOverlay.getPoints());
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath());
painter.drawTrack(canvas);
}
}
@@ -0,0 +1,43 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.maps;
import com.google.android.apps.mytracks.MockMyTracksOverlay;
import com.google.android.maps.MapView;
import android.graphics.Canvas;
import android.test.AndroidTestCase;
/**
* Tests for the MyTracks track path descriptors and painters.
*
* @author Vangelis S.
*/
public class TrackPathPainterTestCase extends AndroidTestCase {
protected Canvas canvas;
protected MockMyTracksOverlay myTracksOverlay;
protected MapView mockView;
@Override
protected void setUp() throws Exception {
super.setUp();
canvas = new Canvas();
myTracksOverlay = new MockMyTracksOverlay(getContext());
// Enable drawing.
myTracksOverlay.setTrackDrawingEnabled(true);
mockView = null;
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
import android.test.AndroidTestCase;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Tests {@link DefaultTrackNameFactory}
*
* @author Matthew Simmons
*/
public class DefaultTrackNameFactoryTest extends AndroidTestCase {
private static final long TRACK_ID = 1L;
private static final long START_TIME = 1288213406000L;
public void testDefaultTrackName_date_local() {
DefaultTrackNameFactory defaultTrackNameFactory = new DefaultTrackNameFactory(getContext()) {
@Override
String getTrackNameSetting() {
return getContext().getString(R.string.settings_recording_track_name_date_local_value);
}
};
assertEquals(StringUtils.formatDateTime(getContext(), START_TIME),
defaultTrackNameFactory.getDefaultTrackName(TRACK_ID, START_TIME));
}
public void testDefaultTrackName_date_iso_8601() {
DefaultTrackNameFactory defaultTrackNameFactory = new DefaultTrackNameFactory(getContext()) {
@Override
String getTrackNameSetting() {
return getContext().getString(R.string.settings_recording_track_name_date_iso_8601_value);
}
};
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
DefaultTrackNameFactory.ISO_8601_FORMAT);
assertEquals(simpleDateFormat.format(new Date(START_TIME)),
defaultTrackNameFactory.getDefaultTrackName(TRACK_ID, START_TIME));
}
public void testDefaultTrackName_number() {
DefaultTrackNameFactory defaultTrackNameFactory = new DefaultTrackNameFactory(getContext()) {
@Override
String getTrackNameSetting() {
return getContext().getString(R.string.settings_recording_track_name_number_value);
}
};
assertEquals(
"Track " + TRACK_ID, defaultTrackNameFactory.getDefaultTrackName(TRACK_ID, START_TIME));
}
}
@@ -0,0 +1,103 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services;
import static com.google.android.testing.mocking.AndroidMock.expect;
import com.google.android.testing.mocking.AndroidMock;
import com.google.android.testing.mocking.UsesMocks;
import android.test.AndroidTestCase;
import java.io.File;
/**
* Tests {@link RemoveTempFilesService}.
*
* @author Sandor Dornbush
*/
public class RemoveTempFilesServiceTest extends AndroidTestCase {
private static final String DIR_NAME = "/tmp";
private static final String FILE_NAME = "foo";
private RemoveTempFilesService service;
@UsesMocks({ File.class, })
protected void setUp() throws Exception {
service = new RemoveTempFilesService();
};
/**
* Tests when the directory doesn't exists.
*/
public void test_noDir() {
File dir = AndroidMock.createMock(File.class, DIR_NAME);
expect(dir.exists()).andStubReturn(false);
AndroidMock.replay(dir);
assertEquals(0, service.cleanTempDirectory(dir));
AndroidMock.verify(dir);
}
/**
* Tests when the directory is empty.
*/
public void test_emptyDir() {
File dir = AndroidMock.createMock(File.class, DIR_NAME);
expect(dir.exists()).andStubReturn(true);
expect(dir.listFiles()).andStubReturn(new File[0]);
AndroidMock.replay(dir);
assertEquals(0, service.cleanTempDirectory(dir));
AndroidMock.verify(dir);
}
/**
* Tests when there is a new file and it shouldn't get deleted.
*/
public void test_newFile() {
File file = AndroidMock.createMock(File.class, DIR_NAME + FILE_NAME);
expect(file.lastModified()).andStubReturn(System.currentTimeMillis());
File dir = AndroidMock.createMock(File.class, DIR_NAME);
expect(dir.exists()).andStubReturn(true);
expect(dir.listFiles()).andStubReturn(new File[] { file });
AndroidMock.replay(dir, file);
assertEquals(0, service.cleanTempDirectory(dir));
AndroidMock.verify(dir, file);
}
/**
* Tests when there is an old file and it should get deleted.
*/
public void test_oldFile() {
File file = AndroidMock.createMock(File.class, DIR_NAME + FILE_NAME);
// qSet to one hour and 1 millisecond later than the current time
expect(file.lastModified()).andStubReturn(System.currentTimeMillis() - 3600001);
expect(file.delete()).andStubReturn(true);
File dir = AndroidMock.createMock(File.class, DIR_NAME);
expect(dir.exists()).andStubReturn(true);
expect(dir.listFiles()).andStubReturn(new File[] { file });
AndroidMock.replay(dir, file);
assertEquals(1, service.cleanTempDirectory(dir));
AndroidMock.verify(dir, file);
}
}
@@ -0,0 +1,64 @@
// Copyright 2012 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.services;
import android.app.Notification;
import android.app.Service;
import android.test.ServiceTestCase;
import android.util.Log;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* A {@link TrackRecordingService} that can be used with {@link ServiceTestCase}.
* {@link ServiceTestCase} throws a null pointer exception when the service
* calls {@link Service#startForeground(int, android.app.Notification)} and
* {@link Service#stopForeground(boolean)}.
* <p>
* See http://code.google.com/p/android/issues/detail?id=12122
* <p>
* Wrap these two methods in wrappers and override them.
*
* @author Jimmy Shih
*/
public class TestRecordingService extends TrackRecordingService {
private static final String TAG = TestRecordingService.class.getSimpleName();
@Override
protected void startForegroundService(Notification notification) {
try {
Method setForegroundMethod = Service.class.getMethod("setForeground", boolean.class);
setForegroundMethod.invoke(this, true);
} catch (SecurityException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (NoSuchMethodException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (IllegalAccessException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (InvocationTargetException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
}
}
@Override
protected void stopForegroundService() {
try {
Method setForegroundMethod = Service.class.getMethod("setForeground", boolean.class);
setForegroundMethod.invoke(this, false);
} catch (SecurityException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (NoSuchMethodException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (IllegalAccessException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
} catch (InvocationTargetException e) {
Log.e(TAG, "Unable to start a service in foreground", e);
}
}
}
@@ -0,0 +1,734 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services;
import static com.google.android.apps.mytracks.Constants.RESUME_TRACK_EXTRA_NAME;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksProvider;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.maps.mytracks.R;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.Location;
import android.os.IBinder;
import android.test.RenamingDelegatingContext;
import android.test.ServiceTestCase;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
/**
* Tests for the MyTracks track recording service.
*
* @author Bartlomiej Niechwiej
*
* TODO: The original class, ServiceTestCase, has a few limitations, e.g.
* it's not possible to properly shutdown the service, unless tearDown()
* is called, which prevents from testing multiple scenarios in a single
* test (see runFunctionTest for more details).
*/
public class TrackRecordingServiceTest extends ServiceTestCase<TestRecordingService> {
private Context context;
private MyTracksProviderUtils providerUtils;
private SharedPreferences sharedPreferences;
/*
* In order to support starting and binding to the service in the same
* unit test, we provide a workaround, as the original class doesn't allow
* to bind after the service has been previously started.
*/
private boolean bound;
private Intent serviceIntent;
public TrackRecordingServiceTest() {
super(TestRecordingService.class);
}
/**
* A context wrapper with the user provided {@link ContentResolver}.
*
* TODO: Move to test utils package.
*/
public static class MockContext extends ContextWrapper {
private final ContentResolver contentResolver;
public MockContext(ContentResolver contentResolver, Context base) {
super(base);
this.contentResolver = contentResolver;
}
@Override
public ContentResolver getContentResolver() {
return contentResolver;
}
}
@Override
protected IBinder bindService(Intent intent) {
if (getService() != null) {
if (bound) {
throw new IllegalStateException(
"Service: " + getService() + " is already bound");
}
bound = true;
serviceIntent = intent.cloneFilter();
return getService().onBind(intent);
} else {
return super.bindService(intent);
}
}
@Override
protected void shutdownService() {
if (bound) {
assertNotNull(getService());
getService().onUnbind(serviceIntent);
bound = false;
}
super.shutdownService();
}
@Override
protected void setUp() throws Exception {
super.setUp();
MockContentResolver mockContentResolver = new MockContentResolver();
RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
getContext(), getContext(), "test.");
context = new MockContext(mockContentResolver, targetContext);
MyTracksProvider provider = new MyTracksProvider();
provider.attachInfo(context, null);
mockContentResolver.addProvider(MyTracksProviderUtils.AUTHORITY, provider);
setContext(context);
providerUtils = MyTracksProviderUtils.Factory.get(context);
sharedPreferences = context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
// Let's use default values.
sharedPreferences.edit().clear().apply();
// Disable auto resume by default.
updateAutoResumePrefs(0, -1);
// No recording track.
Editor editor = sharedPreferences.edit();
editor.putLong(context.getString(R.string.recording_track_key), -1);
editor.apply();
}
@SmallTest
public void testStartable() {
startService(createStartIntent());
assertNotNull(getService());
}
@MediumTest
public void testBindable() {
IBinder service = bindService(createStartIntent());
assertNotNull(service);
}
@MediumTest
public void testResumeAfterReboot_shouldResume() throws Exception {
// Insert a dummy track and mark it as recording track.
createDummyTrack(123, System.currentTimeMillis(), true);
// Clear the number of attempts and set the timeout to 10 min.
updateAutoResumePrefs(0, 10);
// Start the service in "resume" mode (simulates the on-reboot action).
Intent startIntent = createStartIntent();
startIntent.putExtra(RESUME_TRACK_EXTRA_NAME, true);
startService(startIntent);
assertNotNull(getService());
// We expect to resume the previous track.
assertTrue(getService().isRecording());
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertEquals(123, service.getRecordingTrackId());
}
// TODO: shutdownService() has a bug and doesn't set mServiceCreated
// to false, thus preventing from a second call to onCreate().
// Report the bug to Android team. Until then, the following tests
// and checks must be commented out.
//
// TODO: If fixed, remove "disabled" prefix from the test name.
@MediumTest
public void disabledTestResumeAfterReboot_simulateReboot() throws Exception {
updateAutoResumePrefs(0, 10);
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
// Simulate recording a track.
long id = service.startNewTrack();
assertTrue(service.isRecording());
assertEquals(id, service.getRecordingTrackId());
shutdownService();
assertEquals(id, sharedPreferences.getLong(
context.getString(R.string.recording_track_key), -1));
// Start the service in "resume" mode (simulates the on-reboot action).
Intent startIntent = createStartIntent();
startIntent.putExtra(RESUME_TRACK_EXTRA_NAME, true);
startService(startIntent);
assertNotNull(getService());
assertTrue(getService().isRecording());
}
@MediumTest
public void testResumeAfterReboot_noRecordingTrack() throws Exception {
// Insert a dummy track and mark it as recording track.
createDummyTrack(123, System.currentTimeMillis(), false);
// Clear the number of attempts and set the timeout to 10 min.
updateAutoResumePrefs(0, 10);
// Start the service in "resume" mode (simulates the on-reboot action).
Intent startIntent = createStartIntent();
startIntent.putExtra(RESUME_TRACK_EXTRA_NAME, true);
startService(startIntent);
assertNotNull(getService());
// We don't expect to resume the previous track, because it was stopped.
assertFalse(getService().isRecording());
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertEquals(-1, service.getRecordingTrackId());
}
@MediumTest
public void testResumeAfterReboot_expiredTrack() throws Exception {
// Insert a dummy track last updated 20 min ago.
createDummyTrack(123, System.currentTimeMillis() - 20 * 60 * 1000, true);
// Clear the number of attempts and set the timeout to 10 min.
updateAutoResumePrefs(0, 10);
// Start the service in "resume" mode (simulates the on-reboot action).
Intent startIntent = createStartIntent();
startIntent.putExtra(RESUME_TRACK_EXTRA_NAME, true);
startService(startIntent);
assertNotNull(getService());
// We don't expect to resume the previous track, because it has expired.
assertFalse(getService().isRecording());
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertEquals(-1, service.getRecordingTrackId());
}
@MediumTest
public void testResumeAfterReboot_tooManyAttempts() throws Exception {
// Insert a dummy track.
createDummyTrack(123, System.currentTimeMillis(), true);
// Set the number of attempts to max.
updateAutoResumePrefs(
TrackRecordingService.MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS, 10);
// Start the service in "resume" mode (simulates the on-reboot action).
Intent startIntent = createStartIntent();
startIntent.putExtra(RESUME_TRACK_EXTRA_NAME, true);
startService(startIntent);
assertNotNull(getService());
// We don't expect to resume the previous track, because there were already
// too many attempts.
assertFalse(getService().isRecording());
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertEquals(-1, service.getRecordingTrackId());
}
@MediumTest
public void testRecording_noTracks() throws Exception {
List<Track> tracks = providerUtils.getAllTracks();
assertTrue(tracks.isEmpty());
ITrackRecordingService service = bindAndGetService(createStartIntent());
// Test if we start in no-recording mode by default.
assertFalse(service.isRecording());
assertEquals(-1, service.getRecordingTrackId());
}
@MediumTest
public void testRecording_oldTracks() throws Exception {
createDummyTrack(123, -1, false);
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
assertEquals(-1, service.getRecordingTrackId());
}
@MediumTest
public void testRecording_orphanedRecordingTrack() throws Exception {
// Just set recording track to a bogus value.
setRecordingTrack(256);
// Make sure that the service will not start recording and will clear
// the bogus track.
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
assertEquals(-1, service.getRecordingTrackId());
}
/**
* Synchronous/waitable broadcast receiver to be used in testing.
*/
private class BlockingBroadcastReceiver extends BroadcastReceiver {
private static final long MAX_WAIT_TIME_MS = 10000;
private List<Intent> receivedIntents = new ArrayList<Intent>();
public List<Intent> getReceivedIntents() {
return receivedIntents;
}
@Override
public void onReceive(Context ctx, Intent intent) {
Log.d("MyTracksTest", "Got broadcast: " + intent);
synchronized (receivedIntents) {
receivedIntents.add(intent);
receivedIntents.notifyAll();
}
}
public boolean waitUntilReceived(int receiveCount) {
long deadline = System.currentTimeMillis() + MAX_WAIT_TIME_MS;
synchronized (receivedIntents) {
while (receivedIntents.size() < receiveCount) {
try {
// Wait releases synchronized lock until it returns
receivedIntents.wait(500);
} catch (InterruptedException e) {
// Do nothing
}
if (System.currentTimeMillis() > deadline) {
return false;
}
}
}
return true;
}
}
@MediumTest
public void testStartNewTrack_noRecording() throws Exception {
// NOTICE: due to the way Android permissions work, if this fails,
// uninstall the test apk then retry - the test must be installed *after*
// My Tracks (go figure).
// Reference: http://code.google.com/p/android/issues/detail?id=5521
BlockingBroadcastReceiver startReceiver = new BlockingBroadcastReceiver();
String startAction = context.getString(R.string.track_started_broadcast_action);
context.registerReceiver(startReceiver, new IntentFilter(startAction));
List<Track> tracks = providerUtils.getAllTracks();
assertTrue(tracks.isEmpty());
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
long id = service.startNewTrack();
assertTrue(id >= 0);
assertTrue(service.isRecording());
Track track = providerUtils.getTrack(id);
assertNotNull(track);
assertEquals(id, track.getId());
assertEquals(sharedPreferences.getString(context.getString(R.string.default_activity_key), ""),
track.getCategory());
assertEquals(id, sharedPreferences.getLong(
context.getString(R.string.recording_track_key), -1));
assertEquals(id, service.getRecordingTrackId());
// Verify that the start broadcast was received.
assertTrue(startReceiver.waitUntilReceived(1));
List<Intent> receivedIntents = startReceiver.getReceivedIntents();
assertEquals(1, receivedIntents.size());
Intent broadcastIntent = receivedIntents.get(0);
assertEquals(startAction, broadcastIntent.getAction());
assertEquals(id, broadcastIntent.getLongExtra(
context.getString(R.string.track_id_broadcast_extra), -1));
context.unregisterReceiver(startReceiver);
}
@MediumTest
public void testStartNewTrack_alreadyRecording() throws Exception {
createDummyTrack(123, -1, true);
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertTrue(service.isRecording());
// Starting a new track when there is a recording should just return -1L.
long newTrack = service.startNewTrack();
assertEquals(-1L, newTrack);
assertEquals(123, sharedPreferences.getLong(
context.getString(R.string.recording_track_key), 0));
assertEquals(123, service.getRecordingTrackId());
}
@MediumTest
public void testEndCurrentTrack_alreadyRecording() throws Exception {
// See comment above if this fails randomly.
BlockingBroadcastReceiver stopReceiver = new BlockingBroadcastReceiver();
String stopAction = context.getString(R.string.track_stopped_broadcast_action);
context.registerReceiver(stopReceiver, new IntentFilter(stopAction));
createDummyTrack(123, -1, true);
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertTrue(service.isRecording());
// End the current track.
service.endCurrentTrack();
assertFalse(service.isRecording());
assertEquals(-1, sharedPreferences.getLong(
context.getString(R.string.recording_track_key), 0));
assertEquals(-1, service.getRecordingTrackId());
// Verify that the stop broadcast was received.
assertTrue(stopReceiver.waitUntilReceived(1));
List<Intent> receivedIntents = stopReceiver.getReceivedIntents();
assertEquals(1, receivedIntents.size());
Intent broadcastIntent = receivedIntents.get(0);
assertEquals(stopAction, broadcastIntent.getAction());
assertEquals(123, broadcastIntent.getLongExtra(
context.getString(R.string.track_id_broadcast_extra), -1));
context.unregisterReceiver(stopReceiver);
}
@MediumTest
public void testEndCurrentTrack_noRecording() throws Exception {
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
// Ending the current track when there is no recording should not result in any error.
service.endCurrentTrack();
assertEquals(-1, sharedPreferences.getLong(
context.getString(R.string.recording_track_key), 0));
assertEquals(-1, service.getRecordingTrackId());
}
@MediumTest
public void testIntegration_completeRecordingSession() throws Exception {
List<Track> tracks = providerUtils.getAllTracks();
assertTrue(tracks.isEmpty());
fullRecordingSession();
}
@MediumTest
public void testInsertStatisticsMarker_noRecordingTrack() throws Exception {
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
try {
service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
fail("Expecting IllegalStateException");
} catch (IllegalStateException e) {
// Expected.
}
}
@MediumTest
public void testInsertStatisticsMarker_validLocation() throws Exception {
createDummyTrack(123, -1, true);
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertTrue(service.isRecording());
assertEquals(1, service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS));
assertEquals(2, service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS));
Waypoint wpt = providerUtils.getWaypoint(1);
assertEquals(getContext().getString(R.string.marker_statistics_icon_url),
wpt.getIcon());
assertEquals(getContext().getString(R.string.marker_type_statistics),
wpt.getName());
assertEquals(Waypoint.TYPE_STATISTICS, wpt.getType());
assertEquals(123, wpt.getTrackId());
assertEquals(0.0, wpt.getLength());
assertNotNull(wpt.getLocation());
assertNotNull(wpt.getStatistics());
// TODO check the rest of the params.
// TODO: Check waypoint 2.
}
@MediumTest
public void testInsertWaypointMarker_noRecordingTrack() throws Exception {
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
try {
service.insertWaypoint(WaypointCreationRequest.DEFAULT_MARKER);
fail("Expecting IllegalStateException");
} catch (IllegalStateException e) {
// Expected.
}
}
@MediumTest
public void testInsertWaypointMarker_validWaypoint() throws Exception {
createDummyTrack(123, -1, true);
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertTrue(service.isRecording());
assertEquals(1, service.insertWaypoint(WaypointCreationRequest.DEFAULT_MARKER));
Waypoint wpt = providerUtils.getWaypoint(1);
assertEquals(getContext().getString(R.string.marker_waypoint_icon_url),
wpt.getIcon());
assertEquals(getContext().getString(R.string.marker_type_waypoint),
wpt.getName());
assertEquals(Waypoint.TYPE_WAYPOINT, wpt.getType());
assertEquals(123, wpt.getTrackId());
assertEquals(0.0, wpt.getLength());
assertNotNull(wpt.getLocation());
assertNull(wpt.getStatistics());
}
@MediumTest
public void testWithProperties_noAnnouncementFreq() throws Exception {
functionalTest(R.string.announcement_frequency_key, (Object) null);
}
@MediumTest
public void testWithProperties_defaultAnnouncementFreq() throws Exception {
functionalTest(R.string.announcement_frequency_key, 1);
}
@MediumTest
public void testWithProperties_noMaxRecordingDist() throws Exception {
functionalTest(R.string.max_recording_distance_key, (Object) null);
}
@MediumTest
public void testWithProperties_defaultMaxRecordingDist() throws Exception {
functionalTest(R.string.max_recording_distance_key, 5);
}
@MediumTest
public void testWithProperties_noMinRecordingDist() throws Exception {
functionalTest(R.string.min_recording_distance_key, (Object) null);
}
@MediumTest
public void testWithProperties_defaultMinRecordingDist() throws Exception {
functionalTest(R.string.min_recording_distance_key, 2);
}
@MediumTest
public void testWithProperties_noSplitFreq() throws Exception {
functionalTest(R.string.split_frequency_key, (Object) null);
}
@MediumTest
public void testWithProperties_defaultSplitFreqByDist() throws Exception {
functionalTest(R.string.split_frequency_key, 5);
}
@MediumTest
public void testWithProperties_defaultSplitFreqByTime() throws Exception {
functionalTest(R.string.split_frequency_key, -2);
}
@MediumTest
public void testWithProperties_noMetricUnits() throws Exception {
functionalTest(R.string.metric_units_key, (Object) null);
}
@MediumTest
public void testWithProperties_metricUnitsEnabled() throws Exception {
functionalTest(R.string.metric_units_key, true);
}
@MediumTest
public void testWithProperties_metricUnitsDisabled() throws Exception {
functionalTest(R.string.metric_units_key, false);
}
@MediumTest
public void testWithProperties_noMinRecordingInterval() throws Exception {
functionalTest(R.string.min_recording_interval_key, (Object) null);
}
@MediumTest
public void testWithProperties_defaultMinRecordingInterval()
throws Exception {
functionalTest(R.string.min_recording_interval_key, 3);
}
@MediumTest
public void testWithProperties_noMinRequiredAccuracy() throws Exception {
functionalTest(R.string.min_required_accuracy_key, (Object) null);
}
@MediumTest
public void testWithProperties_defaultMinRequiredAccuracy() throws Exception {
functionalTest(R.string.min_required_accuracy_key, 500);
}
@MediumTest
public void testWithProperties_noSensorType() throws Exception {
functionalTest(R.string.sensor_type_key, (Object) null);
}
@MediumTest
public void testWithProperties_zephyrSensorType() throws Exception {
functionalTest(R.string.sensor_type_key,
context.getString(R.string.sensor_type_value_zephyr));
}
private ITrackRecordingService bindAndGetService(Intent intent) {
ITrackRecordingService service = ITrackRecordingService.Stub.asInterface(
bindService(intent));
assertNotNull(service);
return service;
}
private Track createDummyTrack(long id, long stopTime, boolean isRecording) {
Track dummyTrack = new Track();
dummyTrack.setId(id);
dummyTrack.setName("Dummy Track");
TripStatistics tripStatistics = new TripStatistics();
tripStatistics.setStopTime(stopTime);
dummyTrack.setStatistics(tripStatistics);
addTrack(dummyTrack, isRecording);
return dummyTrack;
}
private void updateAutoResumePrefs(int attempts, int timeoutMins) {
Editor editor = sharedPreferences.edit();
editor.putInt(context.getString(
R.string.auto_resume_track_current_retry_key), attempts);
editor.putInt(context.getString(
R.string.auto_resume_track_timeout_key), timeoutMins);
editor.apply();
}
private Intent createStartIntent() {
Intent startIntent = new Intent();
startIntent.setClass(context, TrackRecordingService.class);
return startIntent;
}
private void addTrack(Track track, boolean isRecording) {
assertTrue(track.getId() >= 0);
providerUtils.insertTrack(track);
assertEquals(track.getId(), providerUtils.getTrack(track.getId()).getId());
setRecordingTrack(isRecording ? track.getId() : -1);
}
private void setRecordingTrack(long id) {
Editor editor = sharedPreferences.edit();
editor.putLong(context.getString(R.string.recording_track_key), id);
editor.apply();
}
// TODO: We support multiple values for readability, however this test's
// base class doesn't properly shutdown the service, so it's not possible
// to pass more than 1 value at a time.
private void functionalTest(int resourceId, Object ...values)
throws Exception {
final String key = context.getString(resourceId);
for (Object value : values) {
// Remove all properties and set the property for the given key.
Editor editor = sharedPreferences.edit();
editor.clear();
if (value instanceof String) {
editor.putString(key, (String) value);
} else if (value instanceof Long) {
editor.putLong(key, (Long) value);
} else if (value instanceof Integer) {
editor.putInt(key, (Integer) value);
} else if (value instanceof Boolean) {
editor.putBoolean(key, (Boolean) value);
} else if (value == null) {
// Do nothing, as clear above has already removed this property.
}
editor.apply();
fullRecordingSession();
}
}
private void fullRecordingSession() throws Exception {
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
// Start a track.
long id = service.startNewTrack();
assertTrue(id >= 0);
assertTrue(service.isRecording());
Track track = providerUtils.getTrack(id);
assertNotNull(track);
assertEquals(id, track.getId());
assertEquals(id, sharedPreferences.getLong(
context.getString(R.string.recording_track_key), -1));
assertEquals(id, service.getRecordingTrackId());
// Insert a few points, markers and statistics.
long startTime = System.currentTimeMillis();
for (int i = 0; i < 30; i++) {
Location loc = new Location("gps");
loc.setLongitude(35.0f + i / 10.0f);
loc.setLatitude(45.0f - i / 5.0f);
loc.setAccuracy(5);
loc.setSpeed(10);
loc.setTime(startTime + i * 10000);
loc.setBearing(3.0f);
service.recordLocation(loc);
if (i % 10 == 0) {
service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
} else if (i % 7 == 0) {
service.insertWaypoint(WaypointCreationRequest.DEFAULT_MARKER);
}
}
// Stop the track. Validate if it has correct data.
service.endCurrentTrack();
assertFalse(service.isRecording());
assertEquals(-1, service.getRecordingTrackId());
track = providerUtils.getTrack(id);
assertNotNull(track);
assertEquals(id, track.getId());
TripStatistics tripStatistics = track.getStatistics();
assertNotNull(tripStatistics);
assertTrue(tripStatistics.getStartTime() > 0);
assertTrue(tripStatistics.getStopTime() >= tripStatistics.getStartTime());
}
}
@@ -0,0 +1,70 @@
package com.google.android.apps.mytracks.services.sensors;
import java.util.Arrays;
import com.google.android.apps.mytracks.content.Sensor;
import junit.framework.TestCase;
public class PolarMessageParserTest extends TestCase {
PolarMessageParser parser = new PolarMessageParser();
// A complete and valid Polar HxM packet
// FE08F701D1001104FE08F702D1001104
private final byte[] originalBuf =
{(byte) 0xFE, 0x08, (byte) 0xF7, 0x01, (byte) 0xD1, 0x00, 0x11, 0x04, (byte) 0xFE, 0x08,
(byte) 0xF7, 0x02, (byte) 0xD1, 0x00, 0x11, 0x04};
private byte[] buf;
public void setUp() {
buf = Arrays.copyOf(originalBuf, originalBuf.length);
}
public void testIsValid() {
assertTrue(parser.isValid(buf));
}
public void testIsValid_invalidHeader() {
// Invalidate header.
buf[0] = 0x03;
assertFalse(parser.isValid(buf));
}
public void testIsValid_invalidCheckbyte() {
// Invalidate checkbyte.
buf[2] = 0x03;
assertFalse(parser.isValid(buf));
}
public void testIsValid_invalidSequence() {
// Invalidate sequence.
buf[3] = 0x11;
assertFalse(parser.isValid(buf));
}
public void testParseBuffer() {
buf[5] = 70;
Sensor.SensorDataSet sds = parser.parseBuffer(buf);
assertTrue(sds.hasHeartRate());
assertTrue(sds.getHeartRate().getState() == Sensor.SensorState.SENDING);
assertEquals(70, sds.getHeartRate().getValue());
}
public void testFindNextAlignment_offset() {
// The first 4 bytes are garbage
buf = new byte[originalBuf.length + 4];
buf[0] = 4;
buf[1] = 2;
buf[2] = 4;
buf[3] = 2;
// Then the valid message.
System.arraycopy(originalBuf, 0, buf, 4, originalBuf.length);
assertEquals(4, parser.findNextAlignment(buf));
}
public void testFindNextAlignment_invalid() {
buf[0] = 0;
assertEquals(-1, parser.findNextAlignment(buf));
}
}
@@ -0,0 +1,57 @@
package com.google.android.apps.mytracks.services.sensors;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.services.sensors.ant.AntDirectSensorManager;
import com.google.android.apps.mytracks.services.sensors.ant.AntSrmBridgeSensorManager;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
public class SensorManagerFactoryTest extends AndroidTestCase {
private SharedPreferences sharedPreferences;
@Override
protected void setUp() throws Exception {
super.setUp();
sharedPreferences = getContext().getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
// Let's use default values.
sharedPreferences.edit().clear().apply();
}
@SmallTest
public void testDefaultSettings() throws Exception {
assertNull(SensorManagerFactory.getInstance().getSensorManager(getContext()));
}
@SmallTest
public void testCreateZephyr() throws Exception {
assertClassForName(ZephyrSensorManager.class, R.string.sensor_type_value_zephyr);
}
@SmallTest
public void testCreateAnt() throws Exception {
assertClassForName(AntDirectSensorManager.class, R.string.sensor_type_value_ant);
}
@SmallTest
public void testCreateAntSRM() throws Exception {
assertClassForName(AntSrmBridgeSensorManager.class, R.string.sensor_type_value_srm_ant_bridge);
}
private void assertClassForName(Class<?> c, int i) {
sharedPreferences.edit()
.putString(getContext().getString(R.string.sensor_type_key),
getContext().getString(i))
.apply();
SensorManager sm = SensorManagerFactory.getInstance().getSensorManager(getContext());
assertNotNull(sm);
assertTrue(c.isInstance(sm));
SensorManagerFactory.getInstance().releaseSensorManager(sm);
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services.sensors;
import junit.framework.TestCase;
/**
* @author Dominik Ršttsches
*/
public class StrideReadingsTest extends TestCase {
public void testNoReadingOnStartup() {
StrideReadings strideReadings = new StrideReadings();
assertEquals(StrideReadings.CADENCE_NOT_AVAILABLE, strideReadings.getCadence());
}
public void testAverageCadenceAvailable() {
StrideReadings strideReadings = new StrideReadings();
// 2 steps / second => Cadence is 120 / minute
for (int i = 1; i <= 30; i++) {
strideReadings.updateStrideReading(i*2);
if (i >= StrideReadings.MIN_READINGS_FOR_AVERAGE) {
assertEquals(120, strideReadings.getCadence());
} else {
assertEquals(StrideReadings.CADENCE_NOT_AVAILABLE, strideReadings.getCadence());
}
}
}
/**
* Tests for correct calculation after rolling over at 128 strides,
* just like the HxM seems to do it.
*/
public void testRollover() {
StrideReadings strideReadings = new StrideReadings();
// 1 step per second => Cadence is 60 / minute
// Updating readings counting upwards from initialStrides -
// initialStrides set to a value below 128 to ensure rollover.
int initialStrides = 128 - StrideReadings.NUM_READINGS_FOR_AVERAGE - 5;
for (int i = 1; i <= StrideReadings.NUM_READINGS_FOR_AVERAGE + 10; i++) {
strideReadings.updateStrideReading((initialStrides + i) % 128);
if (i >= StrideReadings.MIN_READINGS_FOR_AVERAGE) {
assertEquals(60, strideReadings.getCadence());
} else {
assertEquals(StrideReadings.CADENCE_NOT_AVAILABLE, strideReadings.getCadence());
}
}
}
}
@@ -0,0 +1,55 @@
package com.google.android.apps.mytracks.services.sensors;
import com.google.android.apps.mytracks.content.Sensor;
import junit.framework.TestCase;
public class ZephyrMessageParserTest extends TestCase {
ZephyrMessageParser parser = new ZephyrMessageParser();
public void testIsValid() {
byte[] smallBuf = new byte[59];
assertFalse(parser.isValid(smallBuf));
// A complete and valid Zephyr HxM packet
byte[] buf = { 2,38,55,26,0,49,101,80,0,49,98,100,42,113,120,-53,-24,-60,-123,-61,117,-69,42,-75,74,-78,51,-79,27,-83,28,-88,28,-93,29,-98,25,-103,26,-108,26,-113,59,-118,0,0,0,0,0,0,-22,3,125,1,48,0,96,4,30,0 };
// Make buffer invalid
buf[0] = buf[58] = buf[59] = 0;
assertFalse(parser.isValid(buf));
buf[0] = 0x02;
assertFalse(parser.isValid(buf));
buf[58] = 0x1E;
assertFalse(parser.isValid(buf));
buf[59] = 0x03;
assertTrue(parser.isValid(buf));
}
public void testParseBuffer() {
byte[] buf = new byte[60];
// Heart Rate (-1 =^ 255 unsigned byte)
buf[12] = -1;
// Battery Level
buf[11] = 51;
// Cadence (=^ 255*16 strides/min)
buf[56] = -1;
buf[57] = 15;
Sensor.SensorDataSet sds = parser.parseBuffer(buf);
assertTrue(sds.hasHeartRate());
assertTrue(sds.getHeartRate().getState() == Sensor.SensorState.SENDING);
assertEquals(255, sds.getHeartRate().getValue());
assertTrue(sds.hasBatteryLevel());
assertTrue(sds.getBatteryLevel().getState() == Sensor.SensorState.SENDING);
assertEquals(51, sds.getBatteryLevel().getValue());
assertTrue(sds.hasCadence());
assertTrue(sds.getCadence().getState() == Sensor.SensorState.SENDING);
assertEquals(255, sds.getCadence().getValue());
}
public void testFindNextAlignment() {
byte[] buf = new byte[60];
assertEquals(-1, parser.findNextAlignment(buf));
buf[10] = 0x03;
buf[11] = 0x02;
assertEquals(10, parser.findNextAlignment(buf));
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services.sensors.ant;
import android.test.AndroidTestCase;
public class AntChannelIdMessageTest extends AndroidTestCase {
public void testParse() {
byte[] rawMessage = {
0, // channel number
0x34, 0x12, // device number
(byte) 0xaa, // device type id
(byte) 0xbb, // transmission type
};
AntChannelIdMessage message = new AntChannelIdMessage(rawMessage);
assertEquals(0, message.getChannelNumber());
assertEquals(0x1234, message.getDeviceNumber());
assertEquals((byte) 0xaa, message.getDeviceTypeId());
assertEquals((byte) 0xbb, message.getTransmissionType());
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services.sensors.ant;
import com.dsi.ant.AntDefine;
import com.dsi.ant.AntMesg;
import android.test.AndroidTestCase;
public class AntChannelResponseMessageTest extends AndroidTestCase {
public void testParse() {
byte[] rawMessage = {
0,
AntMesg.MESG_EVENT_ID,
AntDefine.EVENT_RX_SEARCH_TIMEOUT
};
AntChannelResponseMessage message = new AntChannelResponseMessage(rawMessage);
assertEquals(0, message.getChannelNumber());
assertEquals(AntMesg.MESG_EVENT_ID, message.getMessageId());
assertEquals(AntDefine.EVENT_RX_SEARCH_TIMEOUT, message.getMessageCode());
}
}
@@ -0,0 +1,117 @@
/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services.sensors.ant;
import com.dsi.ant.AntMesg;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
public class AntDirectSensorManagerTest extends AndroidTestCase {
private SharedPreferences sharedPreferences;
private AntSensorBase heartRateSensor;
private static final byte HEART_RATE_CHANNEL = 0;
private class MockAntDirectSensorManager extends AntDirectSensorManager {
public MockAntDirectSensorManager(Context context) {
super(context);
}
@Override
protected boolean setupChannel(AntSensorBase sensor, byte channel) {
if (channel == HEART_RATE_CHANNEL) {
heartRateSensor = sensor;
return true;
}
return false;
}
}
private AntDirectSensorManager manager;
public void setUp() {
sharedPreferences = getContext().getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
// Let's use default values.
sharedPreferences.edit().clear().apply();
manager = new MockAntDirectSensorManager(getContext());
}
@SmallTest
public void testBroadcastData() {
manager.setupAntSensorChannels();
assertNotNull(heartRateSensor);
heartRateSensor.setDeviceNumber((short) 42);
byte[] buff = new byte[9];
buff[0] = HEART_RATE_CHANNEL;
buff[8] = (byte) 220;
manager.handleMessage(AntMesg.MESG_BROADCAST_DATA_ID, buff);
Sensor.SensorDataSet sds = manager.getSensorDataSet();
assertNotNull(sds);
assertTrue(sds.hasHeartRate());
assertEquals(Sensor.SensorState.SENDING,
sds.getHeartRate().getState());
assertEquals(220, sds.getHeartRate().getValue());
assertFalse(sds.hasCadence());
assertFalse(sds.hasPower());
assertEquals(Sensor.SensorState.CONNECTED, manager.getSensorState());
}
@SmallTest
public void testChannelId() {
manager.setupAntSensorChannels();
assertNotNull(heartRateSensor);
byte[] buff = new byte[9];
buff[1] = 43;
manager.handleMessage(AntMesg.MESG_CHANNEL_ID_ID, buff);
assertEquals(43, heartRateSensor.getDeviceNumber());
assertEquals(43,
sharedPreferences.getInt(
getContext().getString(R.string.ant_heart_rate_sensor_id_key), -1));
assertNull(manager.getSensorDataSet());
}
@SmallTest
public void testResponseEvent() {
manager.setupAntSensorChannels();
assertNotNull(heartRateSensor);
manager.setHeartRate(210);
heartRateSensor.setDeviceNumber((short) 42);
assertEquals(Sensor.SensorState.CONNECTED, manager.getSensorState());
byte[] buff = new byte[3];
buff[0] = HEART_RATE_CHANNEL;
buff[1] = AntMesg.MESG_UNASSIGN_CHANNEL_ID;
buff[2] = 0; // code
manager.handleMessage(AntMesg.MESG_RESPONSE_EVENT_ID, buff);
assertEquals(Sensor.SensorState.CONNECTED, manager.getSensorState());
heartRateSensor.setDeviceNumber((short) 0);
manager.handleMessage(AntMesg.MESG_RESPONSE_EVENT_ID, buff);
assertEquals(Sensor.SensorState.DISCONNECTED, manager.getSensorState());
}
// TODO: Test timeout too.
}
@@ -0,0 +1,30 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services.sensors.ant;
import android.test.AndroidTestCase;
public class AntMessageTest extends AndroidTestCase {
private static class TestAntMessage extends AntMessage {
public static short decodeShort(byte low, byte high) {
return AntMessage.decodeShort(low, high);
}
}
public void testDecode() {
assertEquals(0x1234, TestAntMessage.decodeShort((byte) 0x34, (byte) 0x12));
}
}
@@ -0,0 +1,94 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services.sensors.ant;
import android.content.Context;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
public class AntSensorManagerTest extends AndroidTestCase {
private class TestAntSensorManager extends AntSensorManager {
public TestAntSensorManager(Context context) {
super(context);
}
public byte messageId;
public byte[] messageData;
@Override
protected void setupAntSensorChannels() {}
@SuppressWarnings("deprecation")
@Override
public void handleMessage(byte[] rawMessage) {
super.handleMessage(rawMessage);
}
@SuppressWarnings("hiding")
@Override
public boolean handleMessage(byte messageId, byte[] messageData) {
this.messageId = messageId;
this.messageData = messageData;
return true;
}
}
private TestAntSensorManager sensorManager;
@Override
protected void setUp() throws Exception {
super.setUp();
sensorManager = new TestAntSensorManager(getContext());
}
public void testSimple() {
byte[] rawMessage = {
0x03, // length
0x12, // message id
0x11, 0x22, 0x33, // body
};
byte[] expectedBody = { 0x11, 0x22, 0x33 };
sensorManager.handleMessage(rawMessage);
assertEquals((byte) 0x12, sensorManager.messageId);
MoreAsserts.assertEquals(expectedBody, sensorManager.messageData);
}
public void testTooShort() {
byte[] rawMessage = {
0x53, // length
0x12 // message id
};
sensorManager.handleMessage(rawMessage);
assertEquals(0, sensorManager.messageId);
assertNull(sensorManager.messageData);
}
public void testLengthWrong() {
byte[] rawMessage = {
0x53, // length
0x12, // message id
0x34, // body
};
sensorManager.handleMessage(rawMessage);
assertEquals(0, sensorManager.messageId);
assertNull(sensorManager.messageData);
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services.sensors.ant;
import android.test.AndroidTestCase;
public class AntStartupMessageTest extends AndroidTestCase {
public void testParse() {
byte[] rawMessage = {
0x12,
};
AntStartupMessage message = new AntStartupMessage(rawMessage);
assertEquals(0x12, message.getMessage());
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services.sensors.ant;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
/**
* @author Laszlo Molnar
*/
public class SensorEventCounterTest extends AndroidTestCase {
@SmallTest
public void testGetEventsPerMinute() {
SensorEventCounter sec = new SensorEventCounter();
assertEquals(0, sec.getEventsPerMinute(0, 0, 0));
assertEquals(0, sec.getEventsPerMinute(1, 1024, 1000));
assertEquals(60, sec.getEventsPerMinute(2, 1024 * 2, 2000));
assertEquals(60, sec.getEventsPerMinute(2, 1024 * 2, 2500));
assertTrue(60 > sec.getEventsPerMinute(2, 1024 * 2, 4000));
}
}
@@ -0,0 +1,32 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services.tasks;
import android.test.AndroidTestCase;
/**
* Tests for {@link StatusAnnouncerFactory}.
* These tests require Donut+ to run.
*
* @author Rodrigo Damazio
*/
public class StatusAnnouncerFactoryTest extends AndroidTestCase {
public void testCreate() {
PeriodicTaskFactory factory = new StatusAnnouncerFactory();
PeriodicTask task = factory.create(getContext());
assertTrue(task instanceof StatusAnnouncerTask);
}
}
@@ -0,0 +1,552 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services.tasks;
import static com.google.android.testing.mocking.AndroidMock.capture;
import static com.google.android.testing.mocking.AndroidMock.eq;
import static com.google.android.testing.mocking.AndroidMock.expect;
import static com.google.android.testing.mocking.AndroidMock.same;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.testing.mocking.AndroidMock;
import com.google.android.testing.mocking.UsesMocks;
import android.content.Context;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
import java.util.HashMap;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import org.easymock.Capture;
/**
* Tests for {@link StatusAnnouncerTask}.
* WARNING: I'm not responsible if your eyes start bleeding while reading this
* code. You have been warned. It's still better than no test, though.
*
* @author Rodrigo Damazio
*/
public class StatusAnnouncerTaskTest extends AndroidTestCase {
// Use something other than our hardcoded value
private static final Locale DEFAULT_LOCALE = Locale.KOREAN;
private static final String ANNOUNCEMENT = "I can haz cheeseburger?";
private Locale oldDefaultLocale;
private StatusAnnouncerTask task;
private StatusAnnouncerTask mockTask;
private Capture<OnInitListener> initListenerCapture;
private Capture<PhoneStateListener> phoneListenerCapture;
private TextToSpeechDelegate ttsDelegate;
private TextToSpeechInterface tts;
/**
* Mockable interface that we delegate TTS calls to.
*/
interface TextToSpeechInterface {
int addEarcon(String earcon, String packagename, int resourceId);
int addEarcon(String earcon, String filename);
int addSpeech(String text, String packagename, int resourceId);
int addSpeech(String text, String filename);
boolean areDefaultsEnforced();
String getDefaultEngine();
Locale getLanguage();
int isLanguageAvailable(Locale loc);
boolean isSpeaking();
int playEarcon(String earcon, int queueMode,
HashMap<String, String> params);
int playSilence(long durationInMs, int queueMode,
HashMap<String, String> params);
int setEngineByPackageName(String enginePackageName);
int setLanguage(Locale loc);
int setOnUtteranceCompletedListener(OnUtteranceCompletedListener listener);
int setPitch(float pitch);
int setSpeechRate(float speechRate);
void shutdown();
int speak(String text, int queueMode, HashMap<String, String> params);
int stop();
int synthesizeToFile(String text, HashMap<String, String> params,
String filename);
}
/**
* Subclass of {@link TextToSpeech} which delegates calls to the interface
* above.
* The logic here is stupid and the author is ashamed of having to write it
* like this, but basically the issue is that TextToSpeech cannot be mocked
* without running its constructor, its constructor runs async operations
* which call other methods (and then if the methods are part of a mock we'd
* have to set a behavior, but we can't 'cause the object hasn't been fully
* built yet).
* The logic is that calls made during the constructor (when tts is not yet
* set) will go up to the original class, but after tts is set we'll forward
* them all to the mock.
*/
private class TextToSpeechDelegate
extends TextToSpeech implements TextToSpeechInterface {
public TextToSpeechDelegate(Context context, OnInitListener listener) {
super(context, listener);
}
@Override
public int addEarcon(String earcon, String packagename, int resourceId) {
if (tts == null) {
return super.addEarcon(earcon, packagename, resourceId);
}
return tts.addEarcon(earcon, packagename, resourceId);
}
@Override
public int addEarcon(String earcon, String filename) {
if (tts == null) {
return super.addEarcon(earcon, filename);
}
return tts.addEarcon(earcon, filename);
}
@Override
public int addSpeech(String text, String packagename, int resourceId) {
if (tts == null) {
return super.addSpeech(text, packagename, resourceId);
}
return tts.addSpeech(text, packagename, resourceId);
}
@Override
public int addSpeech(String text, String filename) {
if (tts == null) {
return super.addSpeech(text, filename);
}
return tts.addSpeech(text, filename);
}
@Override
public Locale getLanguage() {
if (tts == null) {
return super.getLanguage();
}
return tts.getLanguage();
}
@Override
public int isLanguageAvailable(Locale loc) {
if (tts == null) {
return super.isLanguageAvailable(loc);
}
return tts.isLanguageAvailable(loc);
}
@Override
public boolean isSpeaking() {
if (tts == null) {
return super.isSpeaking();
}
return tts.isSpeaking();
}
@Override
public int playEarcon(String earcon, int queueMode,
HashMap<String, String> params) {
if (tts == null) {
return super.playEarcon(earcon, queueMode, params);
}
return tts.playEarcon(earcon, queueMode, params);
}
@Override
public int playSilence(long durationInMs, int queueMode,
HashMap<String, String> params) {
if (tts == null) {
return super.playSilence(durationInMs, queueMode, params);
}
return tts.playSilence(durationInMs, queueMode, params);
}
@Override
public int setLanguage(Locale loc) {
if (tts == null) {
return super.setLanguage(loc);
}
return tts.setLanguage(loc);
}
@Override
public int setOnUtteranceCompletedListener(
OnUtteranceCompletedListener listener) {
if (tts == null) {
return super.setOnUtteranceCompletedListener(listener);
}
return tts.setOnUtteranceCompletedListener(listener);
}
@Override
public int setPitch(float pitch) {
if (tts == null) {
return super.setPitch(pitch);
}
return tts.setPitch(pitch);
}
@Override
public int setSpeechRate(float speechRate) {
if (tts == null) {
return super.setSpeechRate(speechRate);
}
return tts.setSpeechRate(speechRate);
}
@Override
public void shutdown() {
if (tts == null) {
super.shutdown();
return;
}
tts.shutdown();
}
@Override
public int speak(
String text, int queueMode, HashMap<String, String> params) {
if (tts == null) {
return super.speak(text, queueMode, params);
}
return tts.speak(text, queueMode, params);
}
@Override
public int stop() {
if (tts == null) {
return super.stop();
}
return tts.stop();
}
@Override
public int synthesizeToFile(String text, HashMap<String, String> params,
String filename) {
if (tts == null) {
return super.synthesizeToFile(text, params, filename);
}
return tts.synthesizeToFile(text, params, filename);
}
}
@UsesMocks({
StatusAnnouncerTask.class,
StringUtils.class,
})
@Override
protected void setUp() throws Exception {
super.setUp();
oldDefaultLocale = Locale.getDefault();
Locale.setDefault(DEFAULT_LOCALE);
// Eww, the effort required just to mock TextToSpeech is insane
final AtomicBoolean listenerCalled = new AtomicBoolean();
OnInitListener blockingListener = new OnInitListener() {
@Override
public void onInit(int status) {
synchronized (this) {
listenerCalled.set(true);
notify();
}
}
};
ttsDelegate = new TextToSpeechDelegate(getContext(), blockingListener);
// Wait for all async operations done in the constructor to finish.
synchronized (blockingListener) {
while (!listenerCalled.get()) {
// Releases the synchronized lock until we're woken up.
blockingListener.wait();
}
}
// Phew, done, now we can start forwarding calls
tts = AndroidMock.createMock(TextToSpeechInterface.class);
initListenerCapture = new Capture<OnInitListener>();
phoneListenerCapture = new Capture<PhoneStateListener>();
// Create a partial forwarding mock
mockTask = AndroidMock.createMock(StatusAnnouncerTask.class, getContext());
task = new StatusAnnouncerTask(getContext()) {
@Override
protected TextToSpeech newTextToSpeech(Context ctx,
OnInitListener onInitListener) {
return mockTask.newTextToSpeech(ctx, onInitListener);
}
@Override
protected String getAnnouncement(TripStatistics stats) {
return mockTask.getAnnouncement(stats);
}
@Override
protected void listenToPhoneState(
PhoneStateListener listener, int events) {
mockTask.listenToPhoneState(listener, events);
}
};
}
@Override
protected void tearDown() {
Locale.setDefault(oldDefaultLocale);
}
public void testStart() {
doStart();
OnInitListener ttsInitListener = initListenerCapture.getValue();
assertNotNull(ttsInitListener);
expect(tts.isLanguageAvailable(DEFAULT_LOCALE))
.andStubReturn(TextToSpeech.LANG_AVAILABLE);
expect(tts.setLanguage(DEFAULT_LOCALE))
.andReturn(TextToSpeech.LANG_AVAILABLE);
expect(tts.setSpeechRate(StatusAnnouncerTask.TTS_SPEECH_RATE))
.andReturn(TextToSpeech.SUCCESS);
AndroidMock.replay(tts);
ttsInitListener.onInit(TextToSpeech.SUCCESS);
AndroidMock.verify(mockTask, tts);
}
public void testStart_languageNotSupported() {
doStart();
OnInitListener ttsInitListener = initListenerCapture.getValue();
assertNotNull(ttsInitListener);
expect(tts.isLanguageAvailable(DEFAULT_LOCALE))
.andStubReturn(TextToSpeech.LANG_NOT_SUPPORTED);
expect(tts.setLanguage(Locale.ENGLISH))
.andReturn(TextToSpeech.LANG_AVAILABLE);
expect(tts.setSpeechRate(StatusAnnouncerTask.TTS_SPEECH_RATE))
.andReturn(TextToSpeech.SUCCESS);
AndroidMock.replay(tts);
ttsInitListener.onInit(TextToSpeech.SUCCESS);
AndroidMock.verify(mockTask, tts);
}
public void testStart_notReady() {
doStart();
OnInitListener ttsInitListener = initListenerCapture.getValue();
assertNotNull(ttsInitListener);
AndroidMock.replay(tts);
ttsInitListener.onInit(TextToSpeech.ERROR);
AndroidMock.verify(mockTask, tts);
}
public void testShutdown() {
// First, start
doStart();
AndroidMock.verify(mockTask);
AndroidMock.reset(mockTask);
// Then, shut down
PhoneStateListener phoneListener = phoneListenerCapture.getValue();
mockTask.listenToPhoneState(
same(phoneListener), eq(PhoneStateListener.LISTEN_NONE));
tts.shutdown();
AndroidMock.replay(mockTask, tts);
task.shutdown();
AndroidMock.verify(mockTask, tts);
}
public void testRun() throws Exception {
// Expect service data calls
TripStatistics stats = new TripStatistics();
// Expect announcement building call
expect(mockTask.getAnnouncement(same(stats))).andStubReturn(ANNOUNCEMENT);
// Put task in "ready" state
startTask(TextToSpeech.SUCCESS);
// Expect actual announcement call
expect(tts.speak(
eq(ANNOUNCEMENT), eq(TextToSpeech.QUEUE_FLUSH),
AndroidMock.<HashMap<String, String>>isNull()))
.andReturn(TextToSpeech.SUCCESS);
// Run the announcement
AndroidMock.replay(tts);
task.runWithStatistics(stats);
AndroidMock.verify(mockTask, tts);
}
public void testRun_notReady() throws Exception {
// Put task in "not ready" state
startTask(TextToSpeech.ERROR);
// Run the announcement
AndroidMock.replay(tts);
task.runWithStatistics(null);
AndroidMock.verify(mockTask, tts);
}
public void testRun_duringCall() throws Exception {
startTask(TextToSpeech.SUCCESS);
expect(tts.isSpeaking()).andStubReturn(false);
// Run the announcement
AndroidMock.replay(tts);
PhoneStateListener phoneListener = phoneListenerCapture.getValue();
phoneListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, null);
task.runWithStatistics(null);
AndroidMock.verify(mockTask, tts);
}
public void testRun_ringWhileSpeaking() throws Exception {
startTask(TextToSpeech.SUCCESS);
expect(tts.isSpeaking()).andStubReturn(true);
expect(tts.stop()).andReturn(TextToSpeech.SUCCESS);
AndroidMock.replay(tts);
// Update the state to ringing - this should stop the current announcement.
PhoneStateListener phoneListener = phoneListenerCapture.getValue();
phoneListener.onCallStateChanged(TelephonyManager.CALL_STATE_RINGING, null);
// Run the announcement - this should do nothing.
task.runWithStatistics(null);
AndroidMock.verify(mockTask, tts);
}
public void testRun_whileRinging() throws Exception {
startTask(TextToSpeech.SUCCESS);
expect(tts.isSpeaking()).andStubReturn(false);
// Run the announcement
AndroidMock.replay(tts);
PhoneStateListener phoneListener = phoneListenerCapture.getValue();
phoneListener.onCallStateChanged(TelephonyManager.CALL_STATE_RINGING, null);
task.runWithStatistics(null);
AndroidMock.verify(mockTask, tts);
}
public void testRun_noService() throws Exception {
startTask(TextToSpeech.SUCCESS);
// Run the announcement
AndroidMock.replay(tts);
task.run(null);
AndroidMock.verify(mockTask, tts);
}
public void testRun_noStats() throws Exception {
// Expect service data calls
startTask(TextToSpeech.SUCCESS);
// Run the announcement
AndroidMock.replay(tts);
task.runWithStatistics(null);
AndroidMock.verify(mockTask, tts);
}
/**
* Tests {@link StatusAnnouncerTask#getAnnounceTime(long)} with time zero.
*/
public void testGetAnnounceTime_time_zero() {
long time = 0; // 0 seconds
assertEquals("0 minutes 0 seconds", task.getAnnounceTime(time));
}
/**
* Tests {@link StatusAnnouncerTask#getAnnounceTime(long)} with time one.
*/
public void testGetAnnounceTime_time_one() {
long time = 1 * 1000; // 1 second
assertEquals("0 minutes 1 second", task.getAnnounceTime(time));
}
/**
* Tests {@link StatusAnnouncerTask#getAnnounceTime(long)} with singular
* numbers with the hour unit.
*/
public void testGetAnnounceTime_singular_has_hour() {
long time = (1 * 60 * 60 * 1000) + (1 * 60 * 1000) + (1 * 1000); // 1 hour 1 minute 1 second
assertEquals("1 hour 1 minute", task.getAnnounceTime(time));
}
/**
* Tests {@link StatusAnnouncerTask#getAnnounceTime(long)} with plural numbers
* with the hour unit.
*/
public void testGetAnnounceTime_plural_has_hour() {
long time = (2 * 60 * 60 * 1000) + (2 * 60 * 1000) + (2 * 1000); // 2 hours 2 minutes 2 seconds
assertEquals("2 hours 2 minutes", task.getAnnounceTime(time));
}
/**
* Tests {@link StatusAnnouncerTask#getAnnounceTime(long)} with singular
* numbers without the hour unit.
*/
public void testGetAnnounceTime_singular_no_hour() {
long time = (1 * 60 * 1000) + (1 * 1000); // 1 minute 1 second
assertEquals("1 minute 1 second", task.getAnnounceTime(time));
}
/**
* Tests {@link StatusAnnouncerTask#getAnnounceTime(long)} with plural numbers
* without the hour unit.
*/
public void testGetAnnounceTime_plural_no_hour() {
long time = (2 * 60 * 1000) + (2 * 1000); // 2 minutes 2 seconds
assertEquals("2 minutes 2 seconds", task.getAnnounceTime(time));
}
private void startTask(int state) {
AndroidMock.resetToNice(tts);
AndroidMock.replay(tts);
doStart();
OnInitListener ttsInitListener = initListenerCapture.getValue();
ttsInitListener.onInit(state);
AndroidMock.resetToDefault(tts);
}
private void doStart() {
mockTask.listenToPhoneState(capture(phoneListenerCapture),
eq(PhoneStateListener.LISTEN_CALL_STATE));
expect(mockTask.newTextToSpeech(
same(getContext()), capture(initListenerCapture)))
.andStubReturn(ttsDelegate);
AndroidMock.replay(mockTask);
task.start();
}
}
@@ -0,0 +1,117 @@
/*
* Copyright 2009 Google Inc. All Rights Reserved.
*/
package com.google.android.apps.mytracks.stats;
import junit.framework.TestCase;
/**
* Test for the DoubleBuffer class.
*
* @author Sandor Dornbush
*/
public class DoubleBufferTest extends TestCase {
/**
* Tests that the constructor leaves the buffer in a valid state.
*/
public void testConstructor() {
DoubleBuffer buffer = new DoubleBuffer(10);
assertFalse(buffer.isFull());
assertEquals(0.0, buffer.getAverage());
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(0.0, averageAndVariance[0]);
assertEquals(0.0, averageAndVariance[1]);
}
/**
* Simple test with 10 of the same values.
*/
public void testBasic() {
DoubleBuffer buffer = new DoubleBuffer(10);
for (int i = 0; i < 9; i++) {
buffer.setNext(1.0);
assertFalse(buffer.isFull());
assertEquals(1.0, buffer.getAverage());
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(1.0, averageAndVariance[0]);
assertEquals(0.0, averageAndVariance[1]);
}
buffer.setNext(1);
assertTrue(buffer.isFull());
assertEquals(1.0, buffer.getAverage());
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(1.0, averageAndVariance[0]);
assertEquals(0.0, averageAndVariance[1]);
}
/**
* Tests with 5 entries of -10 and 5 entries of 10.
*/
public void testSplit() {
DoubleBuffer buffer = new DoubleBuffer(10);
for (int i = 0; i < 5; i++) {
buffer.setNext(-10);
assertFalse(buffer.isFull());
assertEquals(-10.0, buffer.getAverage());
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(-10.0, averageAndVariance[0]);
assertEquals(0.0, averageAndVariance[1]);
}
for (int i = 1; i < 5; i++) {
buffer.setNext(10);
assertFalse(buffer.isFull());
double expectedAverage = ((i * 10.0) - 50.0) / (i + 5);
assertEquals(buffer.toString(),
expectedAverage, buffer.getAverage(), 0.01);
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(expectedAverage, averageAndVariance[0]);
}
buffer.setNext(10);
assertTrue(buffer.isFull());
assertEquals(0.0, buffer.getAverage());
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(0.0, averageAndVariance[0]);
assertEquals(100.0, averageAndVariance[1]);
}
/**
* Tests that reset leaves the buffer in a valid state.
*/
public void testReset() {
DoubleBuffer buffer = new DoubleBuffer(10);
for (int i = 0; i < 100; i++) {
buffer.setNext(i);
}
assertTrue(buffer.isFull());
buffer.reset();
assertFalse(buffer.isFull());
assertEquals(0.0, buffer.getAverage());
double[] averageAndVariance = buffer.getAverageAndVariance();
assertEquals(0.0, averageAndVariance[0]);
assertEquals(0.0, averageAndVariance[1]);
}
/**
* Tests that if a lot of items are inserted the smoothing and looping works.
*/
public void testLoop() {
DoubleBuffer buffer = new DoubleBuffer(10);
for (int i = 0; i < 1000; i++) {
buffer.setNext(i);
assertEquals(i >= 9, buffer.isFull());
if (i > 10) {
assertEquals(i - 4.5, buffer.getAverage());
}
}
}
}
@@ -0,0 +1,63 @@
/**
* Copyright 2009 Google Inc. All Rights Reserved.
*/
package com.google.android.apps.mytracks.stats;
import junit.framework.TestCase;
import java.util.Random;
/**
* This class test the ExtremityMonitor class.
*
* @author Sandor Dornbush
*/
public class ExtremityMonitorTest extends TestCase {
public ExtremityMonitorTest(String name) {
super(name);
}
public void testInitialize() {
ExtremityMonitor monitor = new ExtremityMonitor();
assertEquals(Double.POSITIVE_INFINITY, monitor.getMin());
assertEquals(Double.NEGATIVE_INFINITY, monitor.getMax());
}
public void testSimple() {
ExtremityMonitor monitor = new ExtremityMonitor();
assertTrue(monitor.update(0));
assertTrue(monitor.update(1));
assertEquals(0.0, monitor.getMin());
assertEquals(1.0, monitor.getMax());
assertFalse(monitor.update(1));
assertFalse(monitor.update(0.5));
}
/**
* Throws a bunch of random numbers between [0,1] at the monitor.
*/
public void testRandom() {
ExtremityMonitor monitor = new ExtremityMonitor();
Random random = new Random(42);
for (int i = 0; i < 1000; i++) {
monitor.update(random.nextDouble());
}
assertTrue(monitor.getMin() < 0.1);
assertTrue(monitor.getMax() < 1.0);
assertTrue(monitor.getMin() >= 0.0);
assertTrue(monitor.getMax() > 0.9);
}
public void testReset() {
ExtremityMonitor monitor = new ExtremityMonitor();
assertTrue(monitor.update(0));
assertTrue(monitor.update(1));
monitor.reset();
assertEquals(Double.POSITIVE_INFINITY, monitor.getMin());
assertEquals(Double.NEGATIVE_INFINITY, monitor.getMax());
assertTrue(monitor.update(0));
assertTrue(monitor.update(1));
assertEquals(0.0, monitor.getMin());
assertEquals(1.0, monitor.getMax());
}
}
@@ -0,0 +1,184 @@
// Copyright 2009 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.stats;
import com.google.android.apps.mytracks.Constants;
import android.location.Location;
import junit.framework.TestCase;
/**
* Test the the function of the TripStatisticsBuilder class.
*
* @author Sandor Dornbush
*/
public class TripStatisticsBuilderTest extends TestCase {
private TripStatisticsBuilder builder = null;
@Override
protected void setUp() throws Exception {
super.setUp();
builder = new TripStatisticsBuilder(System.currentTimeMillis());
}
public void testAddLocationSimple() throws Exception {
builder = new TripStatisticsBuilder(1000);
TripStatistics stats = builder.getStatistics();
assertEquals(0.0, builder.getSmoothedElevation());
assertEquals(Double.POSITIVE_INFINITY, stats.getMinElevation());
assertEquals(Double.NEGATIVE_INFINITY, stats.getMaxElevation());
assertEquals(0.0, stats.getMaxSpeed());
assertEquals(Double.POSITIVE_INFINITY, stats.getMinGrade());
assertEquals(Double.NEGATIVE_INFINITY, stats.getMaxGrade());
assertEquals(0.0, stats.getTotalElevationGain());
assertEquals(0, stats.getMovingTime());
assertEquals(0.0, stats.getTotalDistance());
for (int i = 0; i < 100; i++) {
Location l = new Location("test");
l.setAccuracy(1.0f);
l.setLongitude(45.0);
// Going up by 5 meters each time.
l.setAltitude(i);
// Moving by .1% of a degree latitude.
l.setLatitude(i * .001);
l.setSpeed(11.1f);
// Each time slice is 10 seconds.
long time = 1000 + 10000 * i;
l.setTime(time);
boolean moving = builder.addLocation(l, time);
assertEquals((i != 0), moving);
stats = builder.getStatistics();
assertEquals(10000 * i, stats.getTotalTime());
assertEquals(10000 * i, stats.getMovingTime());
assertEquals(i, builder.getSmoothedElevation(),
Constants.ELEVATION_SMOOTHING_FACTOR / 2);
assertEquals(0.0, stats.getMinElevation());
assertEquals(i, stats.getMaxElevation(),
Constants.ELEVATION_SMOOTHING_FACTOR / 2);
assertEquals(i, stats.getTotalElevationGain(),
Constants.ELEVATION_SMOOTHING_FACTOR);
if (i > Constants.SPEED_SMOOTHING_FACTOR) {
assertEquals(11.1f, stats.getMaxSpeed(), 0.1);
}
if ((i > Constants.GRADE_SMOOTHING_FACTOR)
&& (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
assertEquals(0.009, stats.getMinGrade(), 0.0001);
assertEquals(0.009, stats.getMaxGrade(), 0.0001);
}
// 1 degree = 111 km
// 1 timeslice = 0.001 degree = 111 m
assertEquals(111.0 * i, stats.getTotalDistance(), 100);
}
}
/**
* Test that elevation works if the user is stable.
*/
public void testElevationSimple() throws Exception {
for (double elevation = 0; elevation < 1000; elevation += 10) {
builder = new TripStatisticsBuilder(System.currentTimeMillis());
for (int j = 0; j < 100; j++) {
assertEquals(0.0, builder.updateElevation(elevation));
assertEquals(elevation, builder.getSmoothedElevation());
TripStatistics data = builder.getStatistics();
assertEquals(elevation, data.getMinElevation());
assertEquals(elevation, data.getMaxElevation());
assertEquals(0.0, data.getTotalElevationGain());
}
}
}
public void testElevationGain() throws Exception {
for (double i = 0; i < 1000; i++) {
double expectedGain;
if (i < (Constants.ELEVATION_SMOOTHING_FACTOR - 1)) {
expectedGain = 0;
} else if (i < Constants.ELEVATION_SMOOTHING_FACTOR) {
expectedGain = 0.5;
} else {
expectedGain = 1.0;
}
assertEquals(expectedGain,
builder.updateElevation(i));
assertEquals(i, builder.getSmoothedElevation(), 20);
TripStatistics data = builder.getStatistics();
assertEquals(0.0, data.getMinElevation(), 0.0);
assertEquals(i, data.getMaxElevation(),
Constants.ELEVATION_SMOOTHING_FACTOR);
assertEquals(i, data.getTotalElevationGain(),
Constants.ELEVATION_SMOOTHING_FACTOR);
}
}
public void testGradeSimple() throws Exception {
for (double i = 0; i < 1000; i++) {
// The value of the elevation does not matter. This is just to fill the
// buffer.
builder.updateElevation(i);
builder.updateGrade(100, 100);
if ((i > Constants.GRADE_SMOOTHING_FACTOR)
&& (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
assertEquals(1.0, builder.getStatistics().getMaxGrade());
assertEquals(1.0, builder.getStatistics().getMinGrade());
}
}
for (double i = 0; i < 1000; i++) {
// The value of the elevation does not matter. This is just to fill the
// buffer.
builder.updateElevation(i);
builder.updateGrade(100, -100);
if ((i > Constants.GRADE_SMOOTHING_FACTOR)
&& (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
assertEquals(1.0, builder.getStatistics().getMaxGrade());
assertEquals(-1.0, builder.getStatistics().getMinGrade());
}
}
}
public void testGradeIgnoreShort() throws Exception {
for (double i = 0; i < 100; i++) {
// The value of the elevation does not matter. This is just to fill the
// buffer.
builder.updateElevation(i);
builder.updateGrade(1, 100);
assertEquals(Double.NEGATIVE_INFINITY, builder.getStatistics().getMaxGrade());
assertEquals(Double.POSITIVE_INFINITY, builder.getStatistics().getMinGrade());
}
}
public void testUpdateSpeedIncludeZero() {
for (int i = 0; i < 1000; i++) {
builder.updateSpeed(i + 1000, 0.0, i, 4.0);
assertEquals(0.0, builder.getStatistics().getMaxSpeed());
assertEquals((i + 1) * 1000, builder.getStatistics().getMovingTime());
}
}
public void testUpdateSpeedIngoreErrorCode() {
builder.updateSpeed(12345000, 128.0, 12344000, 0.0);
assertEquals(0.0, builder.getStatistics().getMaxSpeed());
assertEquals(1000, builder.getStatistics().getMovingTime());
}
public void testUpdateSpeedIngoreLargeAcceleration() {
builder.updateSpeed(12345000, 100.0, 12344000, 1.0);
assertEquals(0.0, builder.getStatistics().getMaxSpeed());
assertEquals(1000, builder.getStatistics().getMovingTime());
}
public void testUpdateSpeed() {
for (int i = 0; i < 1000; i++) {
builder.updateSpeed(i + 1000, 4.0, i, 4.0);
assertEquals((i + 1) * 1000, builder.getStatistics().getMovingTime());
if (i > Constants.SPEED_SMOOTHING_FACTOR) {
assertEquals(4.0, builder.getStatistics().getMaxSpeed());
}
}
}
}
@@ -0,0 +1,105 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.stats;
import junit.framework.TestCase;
/**
* Tests for {@link TripStatistics}.
* This only tests non-trivial pieces of that class.
*
* @author Rodrigo Damazio
*/
public class TripStatisticsTest extends TestCase {
private TripStatistics statistics;
@Override
protected void setUp() throws Exception {
super.setUp();
statistics = new TripStatistics();
}
public void testSetBounds() {
// This is not a trivial setter, conversion happens in it
statistics.setBounds(12345, -34567, 56789, -98765);
assertEquals(12345, statistics.getLeft());
assertEquals(-34567, statistics.getTop());
assertEquals(56789, statistics.getRight());
assertEquals(-98765, statistics.getBottom());
}
public void testMerge() {
TripStatistics statistics2 = new TripStatistics();
statistics.setStartTime(1000L); // Resulting start time
statistics.setStopTime(2500L);
statistics2.setStartTime(3000L);
statistics2.setStopTime(4000L); // Resulting stop time
statistics.setTotalTime(1500L);
statistics2.setTotalTime(1000L); // Result: 1500+1000
statistics.setMovingTime(700L);
statistics2.setMovingTime(600L); // Result: 700+600
statistics.setTotalDistance(750.0);
statistics2.setTotalDistance(350.0); // Result: 750+350
statistics.setTotalElevationGain(50.0);
statistics2.setTotalElevationGain(850.0); // Result: 850+50
statistics.setMaxSpeed(60.0); // Resulting max speed
statistics2.setMaxSpeed(30.0);
statistics.setMaxElevation(1250.0);
statistics.setMinElevation(1200.0); // Resulting min elevation
statistics2.setMaxElevation(3575.0); // Resulting max elevation
statistics2.setMinElevation(2800.0);
statistics.setMaxGrade(15.0);
statistics.setMinGrade(-25.0); // Resulting min grade
statistics2.setMaxGrade(35.0); // Resulting max grade
statistics2.setMinGrade(0.0);
// Resulting bounds: -10000, 35000, 30000, -40000
statistics.setBounds(-10000, 20000, 30000, -40000);
statistics2.setBounds(-5000, 35000, 0, 20000);
statistics.merge(statistics2);
assertEquals(1000L, statistics.getStartTime());
assertEquals(4000L, statistics.getStopTime());
assertEquals(2500L, statistics.getTotalTime());
assertEquals(1300L, statistics.getMovingTime());
assertEquals(1100.0, statistics.getTotalDistance());
assertEquals(900.0, statistics.getTotalElevationGain());
assertEquals(60.0, statistics.getMaxSpeed());
assertEquals(-10000, statistics.getLeft());
assertEquals(30000, statistics.getRight());
assertEquals(35000, statistics.getTop());
assertEquals(-40000, statistics.getBottom());
assertEquals(1200.0, statistics.getMinElevation());
assertEquals(3575.0, statistics.getMaxElevation());
assertEquals(-25.0, statistics.getMinGrade());
assertEquals(35.0, statistics.getMaxGrade());
}
public void testGetAverageSpeed() {
statistics.setTotalDistance(1000.0);
statistics.setTotalTime(50000); // in milliseconds
assertEquals(20.0, statistics.getAverageSpeed());
}
public void testGetAverageMovingSpeed() {
statistics.setTotalDistance(1000.0);
statistics.setMovingTime(20000); // in milliseconds
assertEquals(50.0, statistics.getAverageMovingSpeed());
}
}
@@ -0,0 +1,38 @@
// Copyright 2010 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.testing;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
import android.content.Context;
/**
* A fake factory for {@link MyTracksProviderUtils} which always returns a
* predefined instance.
*
* @author Rodrigo Damazio
*/
public class TestingProviderUtilsFactory extends Factory {
private MyTracksProviderUtils instance;
public TestingProviderUtilsFactory(MyTracksProviderUtils instance) {
this.instance = instance;
}
@Override
protected MyTracksProviderUtils newForContext(Context context) {
return instance;
}
public static Factory installWithInstance(MyTracksProviderUtils instance) {
Factory oldFactory = Factory.getInstance();
Factory factory = new TestingProviderUtilsFactory(instance);
MyTracksProviderUtils.Factory.overrideInstance(factory);
return oldFactory;
}
public static void restoreOldFactory(Factory factory) {
MyTracksProviderUtils.Factory.overrideInstance(factory);
}
}
@@ -0,0 +1,75 @@
/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.stats.TripStatistics;
import java.util.Vector;
import junit.framework.TestCase;
/**
* Tests for the Chart URL generator.
*
* @author Sandor Dornbush
*/
public class ChartURLGeneratorTest extends TestCase {
public void testgetChartUrl() {
Vector<Double> distances = new Vector<Double>();
Vector<Double> elevations = new Vector<Double>();
Track t = new Track();
TripStatistics stats = t.getStatistics();
stats.setMinElevation(0);
stats.setMaxElevation(2000);
stats.setTotalDistance(100);
distances.add(0.0);
elevations.add(10.0);
distances.add(10.0);
elevations.add(300.0);
distances.add(20.0);
elevations.add(800.0);
distances.add(50.0);
elevations.add(1900.0);
distances.add(75.0);
elevations.add(1200.0);
distances.add(90.0);
elevations.add(700.0);
distances.add(100.0);
elevations.add(70.0);
String chart = ChartURLGenerator.getChartUrl(distances,
elevations,
t,
"Title",
true);
assertEquals(
"http://chart.apis.google.com/chart?&chs=600x350&cht=lxy&"
+ "chtt=Title&chxt=x,y&chxr=0,0,0,0|1,0.0,2100.0,300&chco=009A00&"
+ "chm=B,00AA00,0,0,0&chg=100000,14.285714285714286,1,0&"
+ "chd=e:AAGZMzf.v.5l..,ATJJYY55kkVVCI",
chart);
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.util;
import junit.framework.TestCase;
/**
* A unit test for {@link ChartsExtendedEncoder}.
*
* @author Bartlomiej Niechwiej
*/
public class ChartsExtendedEncoderTest extends TestCase {
public void testGetEncodedValue_validArguments() {
// Valid arguments.
assertEquals("AK", ChartsExtendedEncoder.getEncodedValue(10));
assertEquals("JO", ChartsExtendedEncoder.getEncodedValue(590));
assertEquals("AA", ChartsExtendedEncoder.getEncodedValue(0));
// 64^2 = 4096.
assertEquals("..", ChartsExtendedEncoder.getEncodedValue(4095));
}
public void testGetEncodedValue_invalidArguments() {
// Invalid arguments.
assertEquals("__", ChartsExtendedEncoder.getEncodedValue(4096));
assertEquals("__", ChartsExtendedEncoder.getEncodedValue(1234564096));
assertEquals("__", ChartsExtendedEncoder.getEncodedValue(-10));
assertEquals("__", ChartsExtendedEncoder.getEncodedValue(-12324435));
}
public void testGetSeparator() {
assertEquals(",", ChartsExtendedEncoder.getSeparator());
}
}
@@ -0,0 +1,123 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.Constants;
import android.os.Environment;
import java.io.File;
import junit.framework.TestCase;
/**
* Tests for {@link FileUtils}.
*
* @author Rodrigo Damazio
*/
public class FileUtilsTest extends TestCase {
/**
* Tests {@link FileUtils#buildExternalDirectoryPath(String...)}.
*/
public void testBuildExternalDirectoryPath() {
String expectedName = Environment.getExternalStorageDirectory() + File.separator
+ Constants.SDCARD_TOP_DIR + File.separator + "a" + File.separator + "b" + File.separator
+ "c";
String dirName = FileUtils.buildExternalDirectoryPath("a", "b", "c");
assertEquals(expectedName, dirName);
}
/**
* Tests {@link FileUtils#buildUniqueFileName(File, String, String)} when the
* file is new.
*/
public void testBuildUniqueFileName_new() {
String filename = FileUtils.buildUniqueFileName(new File("/dir"), "Filename", "ext");
assertEquals("Filename.ext", filename);
}
/**
* Tests {@link FileUtils#buildUniqueFileName(File, String, String)} when the
* file exists already.
*/
public void testBuildUniqueFileName_exist() {
// Expect "/default.prop" to exist on the phone/emulator
String filename = FileUtils.buildUniqueFileName(new File("/"), "default", "prop");
assertEquals("default(1).prop", filename);
}
/**
* Tests {@link FileUtils#sanitizeFileName(String)} with special characters.
* Verifies that they are sanitized.
*/
public void testSanitizeFileName() {
String name = "Swim\10ming-^across:/the/ pacific (ocean).";
String expected = "Swim_ming-^across_the_ pacific (ocean)_";
assertEquals(expected, FileUtils.sanitizeFileName(name));
}
/**
* Tests {@link FileUtils#sanitizeFileName(String)} with i18n characters (in
* Chinese and Russian). Verifies that they are allowed.
*/
public void testSanitizeFileName_i18n() {
String name = "您好-привет";
String expected = "您好-привет";
assertEquals(expected, FileUtils.sanitizeFileName(name));
}
/**
* Tests {@link FileUtils#sanitizeFileName(String)} with special FAT32
* characters. Verifies that they are allowed.
*/
public void testSanitizeFileName_special_characters() {
String name = "$%'-_@~`!(){}^#&+,;=[] ";
String expected = "$%'-_@~`!(){}^#&+,;=[] ";
assertEquals(expected, FileUtils.sanitizeFileName(name));
}
/**
* Tests {@link FileUtils#sanitizeFileName(String)} with multiple escaped
* characters in a row. Verifies that they are collapsed into one underscore.
*/
public void testSanitizeFileName_collapse() {
String name = "hello//there";
String expected = "hello_there";
assertEquals(expected, FileUtils.sanitizeFileName(name));
}
/**
* Tests {@link FileUtils#truncateFileName(File, String, String)}. Verifies
* the a long file name is truncated.
*/
public void testTruncateFileName() {
File directory = new File("/dir1/dir2/");
String suffix = ".gpx";
char[] name = new char[FileUtils.MAX_FAT32_PATH_LENGTH];
for (int i = 0; i < name.length; i++) {
name[i] = 'a';
}
String nameString = new String(name);
String truncated = FileUtils.truncateFileName(directory, nameString, suffix);
for (int i = 0; i < truncated.length(); i++) {
assertEquals('a', truncated.charAt(i));
}
assertEquals(FileUtils.MAX_FAT32_PATH_LENGTH,
new File(directory, truncated + suffix).getPath().length());
}
}
@@ -0,0 +1,231 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.util;
import android.test.AndroidTestCase;
import java.util.GregorianCalendar;
import java.util.TimeZone;
/**
* Tests for {@link StringUtils}.
*
* @author Rodrigo Damazio
*/
public class StringUtilsTest extends AndroidTestCase {
/**
* Tests {@link StringUtils#formatDateTime(android.content.Context, long)}.
*/
public void testFormatTime() {
// Unix time 0 in UTC is "4:00 PM" in Pacific Standard time zone.
// This test can break if run on a different time zone or with a different
// time format preference.
assertEquals("4:00 PM", StringUtils.formatTime(getContext(), 0L));
}
/**
* Tests {@link StringUtils#formatDateTime(android.content.Context, long)}.
*/
public void testFormatDateTime() {
// Unix time 0 in UTC is "12/31/1969 4:00 PM" in Pacific Standard time zone.
// This test can break if run on a different time zone or with a different
// date/time format preference.
assertEquals("12/31/1969 4:00 PM", StringUtils.formatDateTime(getContext(), 0L));
}
/**
* Tests {@link StringUtils#formatDateTimeIso8601(long)}.
*/
public void testFormatDateTimeIso8601() {
assertEquals("1970-01-01T00:00:12.345Z", StringUtils.formatDateTimeIso8601(12345));
}
/**
* Tests {@link StringUtils#formatElapsedTime(long)}.
*/
public void testformatElapsedTime() {
// 1 second
assertEquals("00:01", StringUtils.formatElapsedTime(1000));
// 10 seconds
assertEquals("00:10", StringUtils.formatElapsedTime(10000));
// 1 minute
assertEquals("01:00", StringUtils.formatElapsedTime(60000));
// 10 minutes
assertEquals("10:00", StringUtils.formatElapsedTime(600000));
// 1 hour
assertEquals("1:00:00", StringUtils.formatElapsedTime(3600000));
// 10 hours
assertEquals("10:00:00", StringUtils.formatElapsedTime(36000000));
// 100 hours
assertEquals("100:00:00", StringUtils.formatElapsedTime(360000000));
}
/**
* Tests {@link StringUtils#formatElapsedTimeWithHour(long)}.
*/
public void testformatElapsedTimeWithHour() {
// 1 second
assertEquals("0:00:01", StringUtils.formatElapsedTimeWithHour(1000));
// 10 seconds
assertEquals("0:00:10", StringUtils.formatElapsedTimeWithHour(10000));
// 1 minute
assertEquals("0:01:00", StringUtils.formatElapsedTimeWithHour(60000));
// 10 minutes
assertEquals("0:10:00", StringUtils.formatElapsedTimeWithHour(600000));
// 1 hour
assertEquals("1:00:00", StringUtils.formatElapsedTimeWithHour(3600000));
// 10 hours
assertEquals("10:00:00", StringUtils.formatElapsedTimeWithHour(36000000));
// 100 hours
assertEquals("100:00:00", StringUtils.formatElapsedTimeWithHour(360000000));
}
/**
* Tests {@link StringUtils#formatDistance(android.content.Context, double,
* boolean)}.
*/
public void testFormatDistance() {
// A large number in metric
assertEquals("5.00 km", StringUtils.formatDistance(getContext(), 5000, true));
// A large number in imperial
assertEquals("3.11 mi", StringUtils.formatDistance(getContext(), 5000, false));
// A small number in metric
assertEquals("100.00 m", StringUtils.formatDistance(getContext(), 100, true));
// A small number in imperial
assertEquals("328.08 ft", StringUtils.formatDistance(getContext(), 100, false));
}
/**
* Tests {@link StringUtils#formatSpeed(android.content.Context, double,
* boolean, boolean)}.
*/
public void testFormatSpeed() {
// Speed in metric
assertEquals("36.00 km/h", StringUtils.formatSpeed(getContext(), 10, true, true));
// Speed in imperial
assertEquals("22.37 mi/h", StringUtils.formatSpeed(getContext(), 10, false, true));
// Pace in metric
assertEquals("1.67 min/km", StringUtils.formatSpeed(getContext(), 10, true, false));
// Pace in imperial
assertEquals("2.68 min/mi", StringUtils.formatSpeed(getContext(), 10, false, false));
// zero pace
assertEquals("0.00 min/km", StringUtils.formatSpeed(getContext(), 0, true, false));
assertEquals("0.00 min/mi", StringUtils.formatSpeed(getContext(), 0, false, false));
// speed is NaN
assertEquals("-", StringUtils.formatSpeed(getContext(), Double.NaN, true, true));
// speed is infinite
assertEquals("-", StringUtils.formatSpeed(getContext(), Double.NEGATIVE_INFINITY, true, true));
}
/**
* Tests {@link StringUtils#formatTimeDistance(android.content.Context, long, double, boolean)}.
*/
public void testFormatTimeDistance() {
assertEquals("00:10 5.00 km", StringUtils.formatTimeDistance(getContext(), 10000, 5000, true));
}
/**
* Tests {@link StringUtils#formatCData(String)}.
*/
public void testFormatCData() {
assertEquals("<![CDATA[hello]]>", StringUtils.formatCData("hello"));
assertEquals("<![CDATA[hello]]]]><![CDATA[>there]]>", StringUtils.formatCData("hello]]>there"));
}
/**
* Tests {@link StringUtils#getTime(String)}.
*/
public void testGetTime() {
assertGetTime("2010-05-04T03:02:01", 2010, 5, 4, 3, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01Z", 2010, 5, 4, 3, 2, 1, 0);
}
/**
* Tests {@link StringUtils#getTime(String)} with fractional seconds.
*/
public void testGetTime_fractional() {
assertGetTime("2010-05-04T03:02:01.3", 2010, 5, 4, 3, 2, 1, 300);
assertGetTime("2010-05-04T03:02:01.35", 2010, 5, 4, 3, 2, 1, 350);
assertGetTime("2010-05-04T03:02:01.352Z", 2010, 5, 4, 3, 2, 1, 352);
assertGetTime("2010-05-04T03:02:01.3525Z", 2010, 5, 4, 3, 2, 1, 352);
}
/**
* Tests {@link StringUtils#getTime(String)} with time zone.
*/
public void testGetTime_timezone() {
assertGetTime("2010-05-04T03:02:01Z", 2010, 5, 4, 3, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01+00:00", 2010, 5, 4, 3, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01-00:00", 2010, 5, 4, 3, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01+01:00", 2010, 5, 4, 2, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01+10:30", 2010, 5, 3, 16, 32, 1, 0);
assertGetTime("2010-05-04T03:02:01-09:30", 2010, 5, 4, 12, 32, 1, 0);
assertGetTime("2010-05-04T03:02:01-05:00", 2010, 5, 4, 8, 2, 1, 0);
}
/**
* Tests {@link StringUtils#getTime(String)} with fractional seconds and time
* zone.
*/
public void testGetTime_fractionalAndTimezone() {
assertGetTime("2010-05-04T03:02:01.352Z", 2010, 5, 4, 3, 2, 1, 352);
assertGetTime("2010-05-04T03:02:01.47+00:00", 2010, 5, 4, 3, 2, 1, 470);
assertGetTime("2010-05-04T03:02:01.5791+03:00", 2010, 5, 4, 0, 2, 1, 579);
assertGetTime("2010-05-04T03:02:01.8-05:30", 2010, 5, 4, 8, 32, 1, 800);
}
/**
* Asserts the {@link StringUtils#getTime(String)} returns the expected
* values.
*
* @param xmlDateTime the xml date time string
* @param year the expected year
* @param month the expected month
* @param day the expected day
* @param hour the expected hour
* @param minute the expected minute
* @param second the expected second
* @param millisecond the expected milliseconds
*/
private void assertGetTime(String xmlDateTime, int year, int month, int day, int hour, int minute,
int second, int millisecond) {
GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.set(year, month - 1, day, hour, minute, second);
calendar.set(GregorianCalendar.MILLISECOND, millisecond);
assertEquals(calendar.getTimeInMillis(), StringUtils.getTime(xmlDateTime));
}
/**
* Tests {@link StringUtils#getTimeParts(long)} with a positive number.
*/
public void testGetTimeParts_postive() {
int parts[] = StringUtils.getTimeParts(61000);
assertEquals(1, parts[0]);
assertEquals(1, parts[1]);
assertEquals(0, parts[2]);
}
/**
* Tests {@link StringUtils#getTimeParts(long)} with a negative number.
*/
public void testGetTimeParts_negative() {
int parts[] = StringUtils.getTimeParts(-61000);
assertEquals(-1, parts[0]);
assertEquals(-1, parts[1]);
assertEquals(0, parts[2]);
}
}