diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..f14a2c2
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,194 @@
+name: Tests
+
+on:
+ pull_request:
+ branches: [ master, v2 ]
+ push:
+ branches: [ master, v2 ]
+
+jobs:
+ # Craft 5.x tests (master branch) - PHP 8.2+
+ craft5-tests:
+ if: github.ref == 'refs/heads/master' || github.base_ref == 'master'
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13-alpine
+ env:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ POSTGRES_DB: postgres
+ ports:
+ - 5432:5432
+ options: >-
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ strategy:
+ matrix:
+ php: [8.2, 8.3]
+
+ name: Craft 5.x - PHP ${{ matrix.php }} Tests
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, pdo_pgsql, bcmath, soap, intl, gd, exif, iconv
+ coverage: xdebug
+
+ - name: Cache Composer packages
+ id: composer-cache
+ uses: actions/cache@v3
+ with:
+ path: vendor
+ key: craft5-${{ runner.os }}-php-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
+ restore-keys: |
+ craft5-${{ runner.os }}-php-${{ matrix.php }}-
+
+ - name: Install dependencies
+ run: composer install --prefer-dist --no-progress --dev
+
+ - name: Setup test environment
+ run: |
+ cp tests/.env.example tests/.env
+ sed -i 's/host=postgres/host=localhost/' tests/.env
+ mkdir -p tests/_craft/storage/runtime
+ mkdir -p tests/_craft/storage/logs
+ mkdir -p tests/_craft/storage/config-deltas
+ mkdir -p tests/_craft/migrations
+ mkdir -p tests/_craft/translations
+ mkdir -p tests/_output
+
+ - name: Build Codeception
+ run: vendor/bin/codecept build
+
+ - name: Run all tests
+ run: vendor/bin/codecept run --coverage --coverage-xml
+ env:
+ CRAFT_DB_DSN: "pgsql:host=localhost;port=5432;dbname=postgres"
+ CRAFT_DB_USER: postgres
+ CRAFT_DB_PASSWORD: postgres
+ CRAFT_DB_SCHEMA: public
+ CRAFT_DB_TABLE_PREFIX: craft
+ CRAFT_SECURITY_KEY: test-security-key-for-github-actions
+
+ - name: Upload coverage reports to Codecov
+ uses: codecov/codecov-action@v3
+ if: matrix.php == '8.2'
+ with:
+ files: ./tests/_output/coverage.xml
+ fail_ci_if_error: false
+ verbose: true
+
+ - name: Generate coverage text report
+ if: github.event_name == 'pull_request' && matrix.php == '8.2'
+ id: coverage
+ run: |
+ raw_output=$(vendor/bin/codecept run unit --coverage-text --no-ansi 2>&1)
+
+ classes=$(echo "$raw_output" | grep "Classes:" | grep -o '[0-9]*\.[0-9]*%' | head -1 || echo "N/A")
+ methods=$(echo "$raw_output" | grep "Methods:" | grep -o '[0-9]*\.[0-9]*%' | head -1 || echo "N/A")
+ lines=$(echo "$raw_output" | grep "Lines:" | grep -o '[0-9]*\.[0-9]*%' | head -1 || echo "N/A")
+
+ test_result=$(echo "$raw_output" | grep "OK (" || echo "Tests completed")
+
+ echo "classes=${classes:-N/A}" >> "$GITHUB_OUTPUT"
+ echo "methods=${methods:-N/A}" >> "$GITHUB_OUTPUT"
+ echo "lines=${lines:-N/A}" >> "$GITHUB_OUTPUT"
+ echo "test-result=${test_result:-Tests completed}" >> "$GITHUB_OUTPUT"
+ env:
+ CRAFT_DB_DSN: "pgsql:host=localhost;port=5432;dbname=postgres"
+ CRAFT_DB_USER: postgres
+ CRAFT_DB_PASSWORD: postgres
+ CRAFT_DB_SCHEMA: public
+ CRAFT_DB_TABLE_PREFIX: craft
+ CRAFT_SECURITY_KEY: test-security-key-for-github-actions
+
+ - name: Comment PR with coverage
+ uses: marocchino/sticky-pull-request-comment@v2
+ if: github.event_name == 'pull_request' && matrix.php == '8.2'
+ with:
+ recreate: true
+ message: |
+ ## 📊 Test Coverage Report (PHP ${{ matrix.php }})
+
+ | Metric | Coverage |
+ |--------|----------|
+ | **Classes** | `${{ steps.coverage.outputs.classes }}` |
+ | **Methods** | `${{ steps.coverage.outputs.methods }}` |
+ | **Lines** | `${{ steps.coverage.outputs.lines }}` |
+
+ **Test Results:** ${{ steps.coverage.outputs.test-result }}
+
+ # Craft 4.x tests (v2 branch) - PHP 8.0+
+ craft4-tests:
+ if: github.ref == 'refs/heads/v2' || github.base_ref == 'v2'
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ php: [8.0, 8.1, 8.2]
+
+ name: Craft 4.x - PHP ${{ matrix.php }} Tests
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv
+ coverage: xdebug
+
+ - name: Cache Composer packages
+ id: composer-cache
+ uses: actions/cache@v3
+ with:
+ path: vendor
+ key: craft4-${{ runner.os }}-php-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
+ restore-keys: |
+ craft4-${{ runner.os }}-php-${{ matrix.php }}-
+
+ - name: Install dependencies
+ run: composer install --prefer-dist --no-progress --dev
+
+ - name: Build Codeception (if exists)
+ run: |
+ if [ -f "vendor/bin/codecept" ]; then
+ vendor/bin/codecept build
+ fi
+
+ - name: Run unit tests (if exists)
+ run: |
+ if [ -f "vendor/bin/codecept" ]; then
+ vendor/bin/codecept run unit
+ else
+ echo "No tests configured for this branch"
+ fi
+
+ code-quality:
+ runs-on: ubuntu-latest
+ name: Code Quality
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 8.2
+ extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv
+
+ - name: Install dependencies
+ run: composer install --prefer-dist --no-progress --dev
+
+ - name: Check PHP syntax
+ run: find src tests -name "*.php" -exec php -l {} \;
diff --git a/.gitignore b/.gitignore
index a17970c..737f155 100755
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
# COMPOSER
/vendor
+composer.lock
# BUILD FILES
/bower_components/*
@@ -30,3 +31,4 @@
!.vscode/extensions.json
config.codekit3
prepros-6.config
+
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..bed6c67
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,35 @@
+# Repository Guidelines
+
+## Project Structure & Module Organization
+- `src/`: Plugin source code (controllers, models, asset bundles, templates, variables).
+- `tests/`: Codeception suites (`unit/`, `functional/`) plus support data in `_support/` and `_data/`.
+- `resources/`: Plugin resources and metadata assets.
+- `vendor/`: Composer-managed dependencies (generated).
+
+## Build, Test, and Development Commands
+- `composer install --dev`: Install runtime + dev dependencies for local development.
+- `composer require wrav/simplesharing`: Install the plugin into a Craft project.
+- `vendor/bin/codecept run`: Run all Codeception tests.
+- `vendor/bin/codecept run unit`: Run unit tests only.
+- `vendor/bin/codecept run functional`: Run functional tests only.
+- `vendor/bin/codecept run --coverage`: Generate a coverage report.
+
+## Coding Style & Naming Conventions
+- Language: PHP 8.2; Craft CMS plugin conventions.
+- Autoloading: PSR-4 namespace `wrav\simplesharing\` mapped to `src/`.
+- File naming: Class files match class names (e.g., `SimpleSharing.php`).
+- Indentation: 4 spaces; keep files ASCII unless existing content requires Unicode.
+
+## Testing Guidelines
+- Framework: Codeception (with PHPUnit under the hood).
+- Suites: `unit` and `functional` are defined by `tests/*.suite.yml`.
+- Naming: Place unit tests in `tests/unit` and functional tests in `tests/functional`; match Codeception naming conventions (e.g., `*Test.php`).
+- Config: Set Craft test environment in `tests/_craft/config/test.php` before running functional tests.
+
+## Commit & Pull Request Guidelines
+- Commits: Use short, imperative, sentence-case summaries (e.g., “Fix coverage summary extraction”); no prefix observed in recent history.
+- PRs: Include a clear description, linked issue (if any), and test results. Add screenshots or recordings for Control Panel UI changes.
+
+## Security & Configuration Tips
+- Do not commit secrets or `.env` files. Use local environment overrides only.
+- Validate changes against Craft’s plugin requirements (`composer.json`) before release.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2746d3d..a97b13d 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
# Simple Sharing Changelog
+## 3.0.0 - 2026-01-14
+### Updated
+- Craft5.x Support Added (^3.0.0 is not backward compatible with Craft4.x, use 2.x branch).
+- Fixed LinkedIn sharing URL to use correct endpoint
+- Updated Tumblr sharing URL format
+
+# Added
+- Added support for functional, integration and unit testing
+
## 2.0.0 - 2022-11-17
### Updated
- Craft4.x Support Added (^2.0.0 is not backward compatible with Craft3.x, use 1.x branch).
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..c5cfa28
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,65 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Project Overview
+
+Simple Sharing is a Craft CMS 5.x plugin that generates social media share links within the Control Panel, allowing quick sharing of entries to Facebook, Twitter, LinkedIn, Mix, Tumblr, and Reddit.
+
+## Commands
+
+```bash
+# Install dependencies
+composer install --dev
+
+# Build Codeception (regenerate actor classes)
+vendor/bin/codecept build
+
+# Check PHP syntax
+find src tests -name "*.php" -exec php -l {} \;
+```
+
+### Running Tests (requires Docker)
+
+Tests require a PostgreSQL database. Use Docker Compose:
+
+```bash
+# Setup test environment
+cp tests/.env.example tests/.env
+
+# Start Docker containers
+docker compose up -d
+
+# Access app container and run tests
+docker exec -it app sh
+vendor/bin/codecept run # All tests
+vendor/bin/codecept run unit # Unit tests only
+vendor/bin/codecept run integration # Integration tests only
+vendor/bin/codecept run --coverage # With coverage
+```
+
+## Architecture
+
+**Plugin Structure** (`src/`):
+- `SimpleSharing.php` - Main plugin class, registers Twig variable and injects CP JavaScript
+- `variables/SimpleSharingVariable.php` - Twig variable providing `craft.simpleSharing.link(url, service)`
+- `models/Settings.php` - Plugin settings (allowedSections, allowedPlatforms)
+- `controllers/DefaultController.php` - Controller for CP actions (`actionUrl`)
+- `assetbundles/simplesharing/` - JavaScript for CP sidebar functionality
+- `templates/settings.twig` - Settings page template
+
+**Key Integration Points**:
+- Registers `simpleSharing` variable on `CraftVariable::EVENT_INIT`
+- Injects JavaScript on `View::EVENT_END_PAGE` for CP requests
+- Extends `craft\base\Plugin` with settings model
+
+**Testing** (`tests/`):
+- Uses Codeception with `unit`, `integration`, and `functional` suites
+- Unit tests: Core functionality without Craft bootstrap
+- Integration tests: Full Craft CMS integration with plugin installed
+- Test config in `codeception.yml` with `\craft\test\Craft` module
+- Database setup: `dbSetup: { clean: true, setupCraft: true }`
+
+## Supported Platforms
+
+facebook, twitter, linkedin, mix, tumblr, reddit
diff --git a/README.md b/README.md
index 163cdda..dcdfc8a 100755
--- a/README.md
+++ b/README.md
@@ -6,12 +6,16 @@ Simple Sharing is a CraftCMS plugin that generates social media share links with
the Craft CP page, allowing you to quickly and easily share entries.
## Requirements
-Current Version: 2.0.0\
-This plugin requires Craft CMS ^4.0.0.
-If you are looking for CraftCMS 3.x support, use current project [Version 1.0.8](https://github.com/wrav/SimpleSharing/tree/1.0.8)
+| Version | Craft CMS | PHP |
+|---------|-----------|-----|
+| ^3.0.0 | ^5.0.0 | ^8.2 |
+| ^2.0.0 | ^4.0.0 | ^8.0.2 |
+| ^1.0.0 | ^3.0.0 | ^7.2.5 |
-If you are looking for CraftCMS 2.5 support, use previous project [version 1.1.5](https://github.com/hut6/SimpleSharing/tree/1.1.5)
+If you are looking for CraftCMS 4.x support, use [Version 2.x](https://github.com/wrav/SimpleSharing/tree/v2)
+
+If you are looking for CraftCMS 3.x support, use [Version 1.0.8](https://github.com/wrav/SimpleSharing/tree/1.0.8)
## Installing
@@ -40,6 +44,42 @@ Your able to generate share links on the fly in a template as followed.
{{ craft.simpleSharing.link(url, 'reddit') }}
```
+## Testing
+
+The plugin includes a comprehensive test suite using Codeception with unit, integration, and functional tests.
+
+### Running Tests
+
+Tests require Docker with PostgreSQL:
+
+```bash
+# Setup test environment
+cp tests/.env.example tests/.env
+
+# Start Docker containers
+docker compose up -d
+
+# Access app container
+docker exec -it app sh
+
+# Run all tests
+vendor/bin/codecept run
+
+# Run specific suites
+vendor/bin/codecept run unit
+vendor/bin/codecept run integration
+vendor/bin/codecept run functional
+
+# Run with coverage report
+vendor/bin/codecept run --coverage
+```
+
+### Test Coverage
+
+- **Unit Tests**: URL generation, input validation, platform support
+- **Integration Tests**: Plugin installation, settings rendering, Craft integration
+- **Functional Tests**: Template variable availability
+
## Credits
Original built while at working at [HutSix](https://hutsix.com.au/) I've since been granted permission to continue development here.
diff --git a/codeception.yml b/codeception.yml
new file mode 100644
index 0000000..c8d4275
--- /dev/null
+++ b/codeception.yml
@@ -0,0 +1,34 @@
+namespace: tests
+actor: Tester
+paths:
+ tests: tests
+ output: tests/_output
+ data: tests/_data
+ support: tests/_support
+ envs: tests/_envs
+bootstrap: _bootstrap.php
+params:
+ - tests/.env
+modules:
+ enabled:
+ - \craft\test\Craft
+ config:
+ \craft\test\Craft:
+ configFile: "tests/_craft/config/test.php"
+ entryUrl: "https://localhost/index.php"
+ projectConfig: {}
+ migrations: []
+ plugins:
+ simple-sharing:
+ class: '\wrav\simplesharing\SimpleSharing'
+ handle: simple-sharing
+ cleanup: true
+ transaction: true
+ dbSetup: { clean: true, setupCraft: true }
+coverage:
+ enabled: true
+ include:
+ - src/*
+ exclude:
+ - tests/*
+ - src/assetbundles/*
diff --git a/composer.json b/composer.json
index 8afd465..bd7fa0d 100755
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,7 @@
"name": "wrav/simplesharing",
"description": "Simple Sharing generates social media share links within CP entry pages, allowing you to quickly & easily share entries.",
"type": "craft-plugin",
- "version": "2.0.0",
+ "version": "3.0.0",
"keywords": [
"craft",
"cms",
@@ -31,8 +31,9 @@
}
],
"require": {
- "php": ">=8.0.0",
- "craftcms/cms": "^4.0.0"
+ "php": "^8.2",
+ "craftcms/cms": "^5.0.0",
+ "vlucas/phpdotenv": "^5.6"
},
"repositories": [
{
@@ -56,9 +57,18 @@
"class": "wrav\\simplesharing\\SimpleSharing"
},
"config": {
+ "platform": {
+ "php": "8.2"
+ },
"allow-plugins": {
"yiisoft/yii2-composer": true,
"craftcms/plugin-installer": true
}
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.4",
+ "codeception/module-yii2": "^1.1",
+ "codeception/module-phpbrowser": "^3.0",
+ "codeception/module-asserts": "^3.0"
}
}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..7bf5b60
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,26 @@
+# Add postgres service for unit testing
+services:
+ postgres:
+ image: postgres:13-alpine
+ container_name: postgres
+ ports:
+ - 5432:5432
+ environment:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ POSTGRES_DB: postgres
+ healthcheck:
+ test: ["CMD", "pg_isready", "-U", "postgres", "-d", "postgres"]
+ interval: 5s
+ retries: 3
+ app:
+ image: craftcms/nginx:8.2-dev
+ container_name: app
+ environment:
+ XDEBUG_CONFIG: client_host=host.docker.internal
+ depends_on:
+ postgres:
+ condition: service_healthy
+ volumes:
+ - .:/app
+ # vendor/bin/codecept run
\ No newline at end of file
diff --git a/src/SimpleSharing.php b/src/SimpleSharing.php
index f25a92d..3fe1b5d 100755
--- a/src/SimpleSharing.php
+++ b/src/SimpleSharing.php
@@ -1,6 +1,6 @@
sections->getAllSections();
+ $sections = Craft::$app->entries->getAllSections();
$optionsSections = [];
foreach ($sections as $section) {
diff --git a/src/assetbundles/simplesharing/SimpleSharingAsset.php b/src/assetbundles/simplesharing/SimpleSharingAsset.php
index a6ae02c..8f65056 100755
--- a/src/assetbundles/simplesharing/SimpleSharingAsset.php
+++ b/src/assetbundles/simplesharing/SimpleSharingAsset.php
@@ -1,6 +1,6 @@
'Facebook',
'twitter' => 'Twitter',
- 'linkedin' => 'LinkedIn',
+ 'linkedin' => 'LinkedIn',
//'pinterest' => 'Pinterest',
'mix' => 'Mix',
- 'tumblr' => 'Tumblr',
+ 'tumblr' => 'Tumblr',
'reddit' => 'Reddit',
];
diff --git a/src/models/Settings.php b/src/models/Settings.php
index 24feec8..cf5cd4c 100755
--- a/src/models/Settings.php
+++ b/src/models/Settings.php
@@ -1,6 +1,6 @@
getenv('CRAFT_DB_DSN'),
+ 'user' => getenv('CRAFT_DB_USER'),
+ 'password' => getenv('CRAFT_DB_PASSWORD'),
+ 'schema' => getenv('CRAFT_DB_SCHEMA'),
+ 'tablePrefix' => getenv('CRAFT_DB_TABLE_PREFIX'),
+];
diff --git a/tests/_craft/config/test.php b/tests/_craft/config/test.php
new file mode 100644
index 0000000..a5b52b4
--- /dev/null
+++ b/tests/_craft/config/test.php
@@ -0,0 +1,5 @@
+amOnPage('?p=/');
+ $I->seeResponseCodeIs(200);
+ }
+
+ public function testPluginTwigVariableExists(FunctionalTester $I): void
+ {
+ // Test that the simpleSharing Twig variable is available
+ $I->amOnPage('?p=/');
+ // This would need a test template that uses {{ craft.simpleSharing }}
+ $I->seeResponseCodeIs(200);
+ }
+}
diff --git a/tests/integration.suite.yml b/tests/integration.suite.yml
new file mode 100644
index 0000000..6f689bc
--- /dev/null
+++ b/tests/integration.suite.yml
@@ -0,0 +1,11 @@
+# Codeception Test Suite Configuration
+#
+# Suite for integration tests with Craft CMS bootstrapped
+
+actor: IntegrationTester
+bootstrap: _bootstrap.php
+modules:
+ enabled:
+ - Asserts
+ - \tests\Helper\Unit
+ step_decorators: ~
diff --git a/tests/integration/PluginIntegrationTest.php b/tests/integration/PluginIntegrationTest.php
new file mode 100644
index 0000000..6b7fc5b
--- /dev/null
+++ b/tests/integration/PluginIntegrationTest.php
@@ -0,0 +1,64 @@
+plugins->getPlugin('simple-sharing');
+
+ $this->assertNotNull($plugin);
+ $this->assertInstanceOf(SimpleSharing::class, $plugin);
+ }
+
+ public function testSettingsModelHasCorrectDefaults(): void
+ {
+ $plugin = SimpleSharing::getInstance();
+ $settings = $plugin->getSettings();
+
+ $this->assertInstanceOf(Settings::class, $settings);
+ $this->assertIsArray($settings->allowedSections);
+ $this->assertIsArray($settings->allowedPlatforms);
+ }
+
+ public function testSettingsHtmlRendersWithSections(): void
+ {
+ $plugin = SimpleSharing::getInstance();
+
+ $reflection = new \ReflectionMethod($plugin, 'settingsHtml');
+ $reflection->setAccessible(true);
+
+ $html = $reflection->invoke($plugin);
+
+ $this->assertIsString($html);
+ $this->assertStringContainsString('allowedSections', $html);
+ $this->assertStringContainsString('allowedPlatforms', $html);
+
+ // Verify platform options are rendered
+ $this->assertStringContainsString('Facebook', $html);
+ $this->assertStringContainsString('Twitter', $html);
+ $this->assertStringContainsString('LinkedIn', $html);
+ }
+
+ public function testSettingsHtmlIncludesSectionsFromCraft(): void
+ {
+ $sections = Craft::$app->entries->getAllSections();
+ $plugin = SimpleSharing::getInstance();
+
+ $reflection = new \ReflectionMethod($plugin, 'settingsHtml');
+ $reflection->setAccessible(true);
+
+ $html = $reflection->invoke($plugin);
+
+ // If there are sections in the system, they should appear in the settings
+ foreach ($sections as $section) {
+ $this->assertStringContainsString($section->name, $html);
+ }
+ }
+}
diff --git a/tests/integration/_bootstrap.php b/tests/integration/_bootstrap.php
new file mode 100644
index 0000000..cac8ad0
--- /dev/null
+++ b/tests/integration/_bootstrap.php
@@ -0,0 +1,4 @@
+assertTrue(class_exists(SimpleSharing::class));
+ }
+
+ public function testPluginExtendsBasePlugin(): void
+ {
+ $reflection = new \ReflectionClass(SimpleSharing::class);
+ $this->assertTrue($reflection->isSubclassOf(\craft\base\Plugin::class));
+ }
+
+ public function testSettingsHtmlMethodExists(): void
+ {
+ $reflection = new \ReflectionClass(SimpleSharing::class);
+
+ $this->assertTrue($reflection->hasMethod('settingsHtml'));
+
+ $method = $reflection->getMethod('settingsHtml');
+ $this->assertTrue($method->isProtected());
+ $this->assertEquals('string', $method->getReturnType()->getName());
+ }
+
+ public function testCreateSettingsModelMethodExists(): void
+ {
+ $reflection = new \ReflectionClass(SimpleSharing::class);
+
+ $this->assertTrue($reflection->hasMethod('createSettingsModel'));
+
+ $method = $reflection->getMethod('createSettingsModel');
+ $this->assertTrue($method->isProtected());
+ }
+
+}
diff --git a/tests/unit/SimpleSharingVariableTest.php b/tests/unit/SimpleSharingVariableTest.php
new file mode 100644
index 0000000..a8b4d41
--- /dev/null
+++ b/tests/unit/SimpleSharingVariableTest.php
@@ -0,0 +1,109 @@
+variable = new SimpleSharingVariable();
+ }
+
+ public function testFacebookLink(): void
+ {
+ $url = 'https://example.com/test-page';
+ $result = $this->variable->link($url, 'facebook');
+
+ $this->assertSame(
+ 'https://www.facebook.com/sharer/sharer.php?u=' . urlencode($url),
+ $result
+ );
+ }
+
+ public function testTwitterLink(): void
+ {
+ $url = 'https://example.com/test-page';
+ $result = $this->variable->link($url, 'twitter');
+
+ $this->assertSame(
+ 'https://twitter.com/intent/tweet?text=' . urlencode($url),
+ $result
+ );
+ }
+
+ public function testLinkedInLink(): void
+ {
+ $url = 'https://example.com/test-page';
+ $result = $this->variable->link($url, 'linkedin');
+
+ $this->assertSame(
+ 'https://www.linkedin.com/shareArticle?mini=true&title=&summary=&source=&url=' . urlencode($url),
+ $result
+ );
+ }
+
+ public function testMixLink(): void
+ {
+ $url = 'https://example.com/test-page';
+ $result = $this->variable->link($url, 'mix');
+
+ $this->assertSame(
+ 'https://mix.com/add?url=' . urlencode($url),
+ $result
+ );
+ }
+
+ public function testTumblrLink(): void
+ {
+ $url = 'https://example.com/test-page';
+ $result = $this->variable->link($url, 'tumblr');
+
+ $this->assertSame(
+ 'https://www.tumblr.com/share/link?url=' . urlencode($url),
+ $result
+ );
+ }
+
+ public function testRedditLink(): void
+ {
+ $url = 'https://example.com/test-page';
+ $result = $this->variable->link($url, 'reddit');
+
+ $this->assertSame(
+ 'http://www.reddit.com/submit?url=' . urlencode($url),
+ $result
+ );
+ }
+
+ public function testUnsupportedService(): void
+ {
+ $url = 'https://example.com/test-page';
+ $result = $this->variable->link($url, 'unsupported-service');
+
+ $this->assertNull($result);
+ }
+
+ public function testEmptyUrl(): void
+ {
+ $result = $this->variable->link('', 'facebook');
+ $this->assertNull($result);
+
+ $result = $this->variable->link(' ', 'facebook');
+ $this->assertNull($result);
+ }
+
+ public function testUrlEncoding(): void
+ {
+ $url = 'https://example.com/test page with spaces & symbols';
+ $result = $this->variable->link($url, 'facebook');
+
+ $this->assertStringContainsString(urlencode($url), $result);
+ $this->assertStringNotContainsString(' ', $result);
+ $this->assertStringNotContainsString('&', $result);
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/_bootstrap.php b/tests/unit/_bootstrap.php
new file mode 100644
index 0000000..a814366
--- /dev/null
+++ b/tests/unit/_bootstrap.php
@@ -0,0 +1 @@
+