diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fdd46a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,102 @@ +<<<<<<< HEAD +<<<<<<< HEAD +__pycache__/ +*.py[cod] +*$py.class +.pytest_cache/ +.coverage +htmlcov/ +dist/ +build/ +*.egg-info/ +.env +.venv/ +venv/ +======= +# Android Studio +*.iml +.gradle/ +build/ +.idea/ +local.properties + +# Kotlin/Java compiled files +*.class +*.dex + +# Dependency directories +/node_modules +/app/build + +# Logging files +*.log + +# Sensitive information +.env +======= +# Android Studio +.idea/ +*.iml +.gradle/ +build/ +captures/ +>>>>>>> pr-4-souravg77-scanmywifi + +# OS generated files +.DS_Store +Thumbs.db +<<<<<<< HEAD +>>>>>>> pr-1-souravg77-scanmywifi +======= + +# Kotlin/Android specific +*.class +*.log +*.apk +*.aar +*.dex +*.module + +# Dependency directories +/node_modules +/jspm_packages + +# Gradle +gradle/ +gradlew +gradlew.bat + +# Local configuration file +local.properties + +# Log files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +/captures + +# Intellij +*.ipr +*.iws + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +.cxx/ + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +lint/reports/ +>>>>>>> pr-4-souravg77-scanmywifi diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..3b23d6d --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,43 @@ +plugins { + id 'com.android.application' + id 'kotlin-android' +} + +android { + compileSdkVersion 30 + defaultConfig { + applicationId "com.wifiscanner" + minSdkVersion 29 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:1.5.21" + implementation 'androidx.core:core-ktx:1.6.0' + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.android.material:material:1.4.0' + + // Testing dependencies + testImplementation 'junit:junit:4.13.2' + testImplementation 'org.mockito:mockito-core:3.11.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' +} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..055ff78 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + kotlin("jvm") version "1.9.0" + id("org.jetbrains.kotlin.plugin.serialization") version "1.9.0" +} + +repositories { + mavenCentral() + google() +} + +dependencies { + // Kotlin standard library + implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.0") + + // Android dependencies + implementation("androidx.core:core-ktx:1.10.1") + implementation("androidx.appcompat:appcompat:1.6.1") + + // Testing dependencies + testImplementation("junit:junit:4.13.2") + testImplementation("org.robolectric:robolectric:4.10.3") + testImplementation("org.mockito:mockito-core:4.11.0") + testImplementation("org.jetbrains.kotlin:kotlin-test:1.9.0") +} + +tasks.test { + useJUnit() +} \ No newline at end of file diff --git a/src/iteration_tracker.py b/src/iteration_tracker.py new file mode 100644 index 0000000..56c18cf --- /dev/null +++ b/src/iteration_tracker.py @@ -0,0 +1,173 @@ +from __future__ import annotations +from typing import Optional, Dict, Any +from dataclasses import dataclass, field +from enum import Enum, auto +import logging + +class IterationStatus(Enum): + """Enum representing the status of an iteration.""" + INITIALIZED = auto() + IN_PROGRESS = auto() + COMPLETED = auto() + FAILED = auto() + TERMINATED = auto() + +@dataclass +class IterationState: + """Tracks the state and metadata of learning iterations.""" + current_iteration: int = 0 + max_iterations: Optional[int] = None + status: IterationStatus = IterationStatus.INITIALIZED + metadata: Dict[str, Any] = field(default_factory=dict) + + def increment(self) -> None: + """ + Increment the iteration count and update status. + + Raises: + StopIteration: If maximum iterations are reached. + """ + self.current_iteration += 1 + + if self.max_iterations is not None and self.current_iteration > self.max_iterations: + self.status = IterationStatus.COMPLETED + raise StopIteration("Maximum iterations reached") + + self.status = IterationStatus.IN_PROGRESS + + def reset(self) -> None: + """Reset the iteration state to initial conditions.""" + self.current_iteration = 0 + self.status = IterationStatus.INITIALIZED + self.metadata.clear() + + def set_status(self, status: IterationStatus) -> None: + """ + Set the current iteration status. + + Args: + status (IterationStatus): New status to set + """ + self.status = status + + def add_metadata(self, key: str, value: Any) -> None: + """ + Add metadata to the current iteration. + + Args: + key (str): Metadata key + value (Any): Metadata value + """ + self.metadata[key] = value + + @property + def is_complete(self) -> bool: + """ + Check if iteration is complete. + + Returns: + bool: True if iteration is completed, False otherwise + """ + return self.status in {IterationStatus.COMPLETED, IterationStatus.TERMINATED, IterationStatus.FAILED} + +class IterationTracker: + """ + Manages the iteration tracking process for the Adaptive Learning Process. + + Provides comprehensive tracking of iterations with configurable maximum + iterations and detailed state management. + """ + + def __init__(self, max_iterations: Optional[int] = None, logger: Optional[logging.Logger] = None): + """ + Initialize the iteration tracker. + + Args: + max_iterations (Optional[int], optional): Maximum number of iterations. Defaults to None. + logger (Optional[logging.Logger], optional): Logger instance. Defaults to None. + """ + self._state = IterationState(max_iterations=max_iterations) + self._logger = logger or logging.getLogger(__name__) + + def start(self) -> None: + """Start the iteration tracking process.""" + self._state.reset() + self._logger.info("Iteration tracking started") + + def next_iteration(self) -> int: + """ + Move to the next iteration. + + Returns: + int: Current iteration number + + Raises: + StopIteration: If maximum iterations are reached + """ + try: + self._state.increment() + self._logger.info(f"Starting iteration {self._state.current_iteration}") + return self._state.current_iteration + except StopIteration: + self._logger.info("Maximum iterations reached") + raise + + def mark_iteration_complete(self, metadata: Optional[Dict[str, Any]] = None) -> None: + """ + Mark the current iteration as complete. + + Args: + metadata (Optional[Dict[str, Any]], optional): Additional metadata about the iteration. Defaults to None. + """ + if metadata: + for key, value in metadata.items(): + self._state.add_metadata(key, value) + + self._state.set_status(IterationStatus.COMPLETED) + self._logger.info(f"Iteration {self._state.current_iteration} completed") + + def mark_iteration_failed(self, error: Optional[Exception] = None) -> None: + """ + Mark the current iteration as failed. + + Args: + error (Optional[Exception], optional): Error that caused the failure. Defaults to None. + """ + self._state.set_status(IterationStatus.FAILED) + + if error: + self._logger.error(f"Iteration {self._state.current_iteration} failed: {error}") + self._state.add_metadata('error', str(error)) + + def terminate(self, reason: Optional[str] = None) -> None: + """ + Terminate the iteration process. + + Args: + reason (Optional[str], optional): Reason for termination. Defaults to None. + """ + self._state.set_status(IterationStatus.TERMINATED) + + if reason: + self._logger.warning(f"Iteration process terminated: {reason}") + self._state.add_metadata('termination_reason', reason) + + @property + def current_iteration(self) -> int: + """ + Get the current iteration number. + + Returns: + int: Current iteration number + """ + return self._state.current_iteration + + @property + def is_complete(self) -> bool: + """ + Check if iteration process is complete. + + Returns: + bool: True if iterations are complete, False otherwise + """ + return self._state.is_complete \ No newline at end of file diff --git a/src/main/kotlin/com/wifiscanner/models/WiFiSecurity.kt b/src/main/kotlin/com/wifiscanner/models/WiFiSecurity.kt new file mode 100644 index 0000000..7c39864 --- /dev/null +++ b/src/main/kotlin/com/wifiscanner/models/WiFiSecurity.kt @@ -0,0 +1,14 @@ +package com.wifiscanner.models + +/** + * Represents the security type of a WiFi network. + * + * @property type The human-readable security type + * @property description A detailed description of the security type + * @property level A numeric representation of security strength (higher is more secure) + */ +data class WiFiSecurityType( + val type: String, + val description: String, + val level: Int +) \ No newline at end of file diff --git a/src/main/kotlin/com/wifiscanner/network/SecurityTypeDetector.kt b/src/main/kotlin/com/wifiscanner/network/SecurityTypeDetector.kt new file mode 100644 index 0000000..be183b1 --- /dev/null +++ b/src/main/kotlin/com/wifiscanner/network/SecurityTypeDetector.kt @@ -0,0 +1,72 @@ +package com.wifiscanner.network + +import android.net.wifi.ScanResult +import android.util.Log + +/** + * Enum representing WiFi security types with error handling capabilities + */ +enum class SecurityType { + OPEN, + WEP, + WPA, + WPA2, + WPA3, + UNKNOWN +} + +/** + * Handles detection of WiFi network security types with robust error management + */ +class SecurityTypeDetector { + companion private const val TAG = "SecurityTypeDetector" + + /** + * Detect security type of a WiFi network with comprehensive error handling + * @param scanResult The WiFi scan result to analyze + * @return Detected security type, defaults to UNKNOWN if detection fails + */ + fun detectSecurityType(scanResult: ScanResult?): SecurityType { + // Handle null input gracefully + if (scanResult == null) { + Log.w(TAG, "Null ScanResult provided. Returning UNKNOWN security type.") + return SecurityType.UNKNOWN + } + + return try { + when { + // Check for specific security capabilities + scanResult.capabilities.contains("WPA3", ignoreCase = true) -> SecurityType.WPA3 + scanResult.capabilities.contains("WPA2", ignoreCase = true) -> SecurityType.WPA2 + scanResult.capabilities.contains("WPA", ignoreCase = true) -> SecurityType.WPA + scanResult.capabilities.contains("WEP", ignoreCase = true) -> SecurityType.WEP + scanResult.capabilities.isEmpty() -> SecurityType.OPEN + else -> { + // Log non-standard or unrecognized security type + Log.i(TAG, "Unrecognized security type: ${scanResult.capabilities}") + SecurityType.UNKNOWN + } + } + } catch (e: Exception) { + // Catch and log any unexpected errors during security type detection + Log.e(TAG, "Error detecting security type: ${e.message}", e) + SecurityType.UNKNOWN + } + } + + /** + * Provides a human-readable description of the security type + * @param securityType The security type to describe + * @return A descriptive string of the security type + */ + fun getSecurityDescription(securityType: SecurityType): String { + return when (securityType) { + SecurityType.OPEN -> "Open Network (No Security)" + SecurityType.WEP -> "WEP Protected Network" + SecurityType.WPA -> "WPA Protected Network" + SecurityType.WPA2 -> "WPA2 Protected Network" + SecurityType.WPA3 -> "WPA3 Protected Network" + SecurityType.UNKNOWN -> "Unknown Security Type" + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/wifiscanner/utils/WiFiSecurityMapper.kt b/src/main/kotlin/com/wifiscanner/utils/WiFiSecurityMapper.kt new file mode 100644 index 0000000..d9a08a7 --- /dev/null +++ b/src/main/kotlin/com/wifiscanner/utils/WiFiSecurityMapper.kt @@ -0,0 +1,72 @@ +package com.wifiscanner.utils + +import com.wifiscanner.models.WiFiSecurityType + +/** + * Utility class for mapping WiFi network capabilities to security types. + */ +object WiFiSecurityMapper { + /** + * Maps raw network capabilities to a WiFiSecurityType. + * + * @param capabilities Raw network capabilities string + * @return WiFiSecurityType representing the network's security + */ + fun mapSecurityType(capabilities: String?): WiFiSecurityType { + return when { + capabilities.isNullOrBlank() -> WiFiSecurityType( + "Unknown", + "Unable to determine network security", + 0 + ) + capabilities.contains("WPA3", ignoreCase = true) -> WiFiSecurityType( + "WPA3", + "Most advanced WiFi security protocol", + 5 + ) + capabilities.contains("WPA2", ignoreCase = true) -> WiFiSecurityType( + "WPA2", + "Strong encryption with improved security over WPA", + 4 + ) + capabilities.contains("WPA", ignoreCase = true) -> WiFiSecurityType( + "WPA", + "Older security protocol with moderate protection", + 3 + ) + capabilities.contains("WEP", ignoreCase = true) -> WiFiSecurityType( + "WEP", + "Weak and outdated security protocol", + 1 + ) + capabilities.contains("Open", ignoreCase = true) -> WiFiSecurityType( + "Open", + "No encryption, completely unsecured network", + 0 + ) + else -> WiFiSecurityType( + "Other", + "Unrecognized security type", + 2 + ) + } + } + + /** + * Generates a color based on the security level. + * + * @param securityType WiFiSecurityType to determine color for + * @return Color resource ID representing security level + */ + fun getSecurityColor(securityType: WiFiSecurityType): Int { + return when (securityType.level) { + 0 -> android.R.color.holo_red_dark // Open/No Security + 1 -> android.R.color.holo_red_light // Very Weak + 2 -> android.R.color.holo_orange_dark // Weak + 3 -> android.R.color.holo_orange_light // Moderate + 4 -> android.R.color.holo_green_light // Strong + 5 -> android.R.color.holo_green_dark // Most Secure + else -> android.R.color.darker_gray // Unknown + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/wifiscanner/network/SecurityTypeDetectorTest.kt b/src/test/kotlin/com/wifiscanner/network/SecurityTypeDetectorTest.kt new file mode 100644 index 0000000..ec0776c --- /dev/null +++ b/src/test/kotlin/com/wifiscanner/network/SecurityTypeDetectorTest.kt @@ -0,0 +1,76 @@ +package com.wifiscanner.network + +import android.net.wifi.ScanResult +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class SecurityTypeDetectorTest { + + private val detector = SecurityTypeDetector() + + @Test + fun `test null scan result returns UNKNOWN`() { + val result = detector.detectSecurityType(null) + assertEquals(SecurityType.UNKNOWN, result) + } + + @Test + fun `test open network detection`() { + val mockScanResult = Mockito.mock(ScanResult::class.java) + Mockito.`when`(mockScanResult.capabilities).thenReturn("") + + val result = detector.detectSecurityType(mockScanResult) + assertEquals(SecurityType.OPEN, result) + } + + @Test + fun `test WPA3 network detection`() { + val mockScanResult = Mockito.mock(ScanResult::class.java) + Mockito.`when`(mockScanResult.capabilities).thenReturn("[WPA3-PSK-CCMP]") + + val result = detector.detectSecurityType(mockScanResult) + assertEquals(SecurityType.WPA3, result) + } + + @Test + fun `test WPA2 network detection`() { + val mockScanResult = Mockito.mock(ScanResult::class.java) + Mockito.`when`(mockScanResult.capabilities).thenReturn("[WPA2-PSK-CCMP]") + + val result = detector.detectSecurityType(mockScanResult) + assertEquals(SecurityType.WPA2, result) + } + + @Test + fun `test WPA network detection`() { + val mockScanResult = Mockito.mock(ScanResult::class.java) + Mockito.`when`(mockScanResult.capabilities).thenReturn("[WPA-PSK-CCMP]") + + val result = detector.detectSecurityType(mockScanResult) + assertEquals(SecurityType.WPA, result) + } + + @Test + fun `test WEP network detection`() { + val mockScanResult = Mockito.mock(ScanResult::class.java) + Mockito.`when`(mockScanResult.capabilities).thenReturn("[WEP]") + + val result = detector.detectSecurityType(mockScanResult) + assertEquals(SecurityType.WEP, result) + } + + @Test + fun `test security description mapping`() { + val detector = SecurityTypeDetector() + assertEquals("Open Network (No Security)", detector.getSecurityDescription(SecurityType.OPEN)) + assertEquals("WEP Protected Network", detector.getSecurityDescription(SecurityType.WEP)) + assertEquals("WPA Protected Network", detector.getSecurityDescription(SecurityType.WPA)) + assertEquals("WPA2 Protected Network", detector.getSecurityDescription(SecurityType.WPA2)) + assertEquals("WPA3 Protected Network", detector.getSecurityDescription(SecurityType.WPA3)) + assertEquals("Unknown Security Type", detector.getSecurityDescription(SecurityType.UNKNOWN)) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/wifiscanner/utils/WiFiSecurityMapperTest.kt b/src/test/kotlin/com/wifiscanner/utils/WiFiSecurityMapperTest.kt new file mode 100644 index 0000000..bff3f64 --- /dev/null +++ b/src/test/kotlin/com/wifiscanner/utils/WiFiSecurityMapperTest.kt @@ -0,0 +1,57 @@ +package com.wifiscanner.utils + +import com.wifiscanner.models.WiFiSecurityType +import org.junit.Assert.* +import org.junit.Test + +class WiFiSecurityMapperTest { + + @Test + fun `mapSecurityType should return WPA3 for WPA3 capabilities`() { + val capabilities = "[WPA3-PSK-CCMP]" + val result = WiFiSecurityMapper.mapSecurityType(capabilities) + + assertEquals("WPA3", result.type) + assertEquals("Most advanced WiFi security protocol", result.description) + assertEquals(5, result.level) + } + + @Test + fun `mapSecurityType should return WPA2 for WPA2 capabilities`() { + val capabilities = "[WPA2-PSK-CCMP]" + val result = WiFiSecurityMapper.mapSecurityType(capabilities) + + assertEquals("WPA2", result.type) + assertEquals("Strong encryption with improved security over WPA", result.description) + assertEquals(4, result.level) + } + + @Test + fun `mapSecurityType should return Open for open network`() { + val capabilities = "" + val result = WiFiSecurityMapper.mapSecurityType(capabilities) + + assertEquals("Open", result.type) + assertEquals("No encryption, completely unsecured network", result.description) + assertEquals(0, result.level) + } + + @Test + fun `mapSecurityType should return Unknown for null capabilities`() { + val capabilities = null + val result = WiFiSecurityMapper.mapSecurityType(capabilities) + + assertEquals("Unknown", result.type) + assertEquals("Unable to determine network security", result.description) + assertEquals(0, result.level) + } + + @Test + fun `getSecurityColor returns correct color for different security levels`() { + val openSecurity = WiFiSecurityType("Open", "Unsecured", 0) + val wpa3Security = WiFiSecurityType("WPA3", "Secure", 5) + + assertEquals(android.R.color.holo_red_dark, WiFiSecurityMapper.getSecurityColor(openSecurity)) + assertEquals(android.R.color.holo_green_dark, WiFiSecurityMapper.getSecurityColor(wpa3Security)) + } +} \ No newline at end of file diff --git a/tests/test_iteration_tracker.py b/tests/test_iteration_tracker.py new file mode 100644 index 0000000..c32e1a1 --- /dev/null +++ b/tests/test_iteration_tracker.py @@ -0,0 +1,54 @@ +import pytest +import logging +from src.iteration_tracker import IterationTracker, IterationStatus + +def test_iteration_tracker_initialization(): + tracker = IterationTracker() + assert tracker.current_iteration == 0 + assert not tracker.is_complete + +def test_iteration_tracker_with_max_iterations(): + tracker = IterationTracker(max_iterations=3) + + tracker.start() + assert tracker.next_iteration() == 1 + assert tracker.next_iteration() == 2 + assert tracker.next_iteration() == 3 + + with pytest.raises(StopIteration): + tracker.next_iteration() + +def test_iteration_tracker_mark_complete(): + tracker = IterationTracker() + tracker.start() + + iteration = tracker.next_iteration() + tracker.mark_iteration_complete({'result': 'success'}) + + assert iteration == 1 + +def test_iteration_tracker_mark_failed(): + tracker = IterationTracker() + tracker.start() + + iteration = tracker.next_iteration() + tracker.mark_iteration_failed(ValueError("Test error")) + + assert iteration == 1 + +def test_iteration_tracker_terminate(): + tracker = IterationTracker() + tracker.start() + + tracker.terminate("Test termination") + assert tracker.is_complete + +def test_iteration_tracker_metadata(): + tracker = IterationTracker() + tracker.start() + + tracker.next_iteration() + tracker.mark_iteration_complete({'metric': 0.95, 'converged': True}) + + # Note: Actual metadata validation would require more complex mocking/inspection + assert tracker.current_iteration == 1 \ No newline at end of file