diff --git a/.github/workflows/all_test.yaml b/.github/workflows/all_test.yaml new file mode 100644 index 0000000..673524e --- /dev/null +++ b/.github/workflows/all_test.yaml @@ -0,0 +1,29 @@ +name: flutter test + +on: + pull_request: + branches: [ "main", "develop" ] + +jobs: + tests: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - uses: dart-lang/setup-dart@v1 + with: + sdk: 3.10.4 + + - uses: subosito/flutter-action@v2.3.0 + with: + flutter-version: '3.10.3' + + - name: Install dependencies + run: flutter pub get + + - name: Analyze project source + run: flutter analyze + + - name: Run tests + run: flutter test --exclude-tags UseNetwork diff --git a/.gitignore b/.gitignore index 96486fd..959100c 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ migrate_working_dir/ .dart_tool/ .packages build/ + +.fvm/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 41cc7d8..19e35d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ -## 0.0.1 - -* TODO: Describe initial release. +## 1.0.0 +create initial release. +## 1.1.0 +Changed the import file to be only camel.dart diff --git a/LICENSE b/LICENSE index ba75c69..9861611 100644 --- a/LICENSE +++ b/LICENSE @@ -1 +1,21 @@ -TODO: Add your license here. +MIT License + +Copyright (c) 2023 RikitoNoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 02fe8ec..4e578d5 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,100 @@ - - -TODO: Put a short description of the package here that helps potential users -know whether this package might be useful for them. +Flutter package that allows communicating in a local network. ## Features - -TODO: List what your package can do. Maybe include images, gifs, or videos. +This library allows you to communicate in a local network without "dart:io" package. +Also, you can switch callback communication or stream communication. ## Getting started +Add this package to your pubspec.yaml +```yaml +# pubspec.yaml -TODO: List prerequisites and provide or point to information on how to -start using the package. +dependencies: + camel: ^ +``` ## Usage -TODO: Include short and useful examples for package users. Add longer examples -to `/example` folder. +### Sender +If the receiver doesn't use a command callback, you call the send method as below. +```dart + // if you use socket communication and TCP. + final Communicator communicator = Tcp(); + final Camel sender = Camel(communicator); + + // call send method with a connection point a send message. + sender.send( + SocketConnectionPoint(address: "127.0.0.1", port: 50000), + Message.fromBody(command: "dummy", body: "Hello, Camel."), + ); +``` +When using a command callback, you define a custom command class as below. ```dart -const like = 'sample'; + class MyCommand implements Command { + @override String get command => "MY_COMMAND"; + + @override + void execute(Uint8List data){ + // This method is called when data is received by the Camel.listen method. + print("received: ${utf8.decode(data)}"); // received: Hello, Camel. + } + } + + // if you use socket communication and TCP. + final Communicator communicator = Tcp(); + final Camel sender = Camel(communicator); + CommandFactory.registerCommand(MyCommand()); // register command. + + // call send method with a connection point a send message. + sender.send( + SocketConnectionPoint(address: "127.0.0.1", port: 50000), + Message.fromBody(command: "MY_COMMAND", body: "Hello, Camel."), + ); ``` -## Additional information +### Receiver +If the receiver doesn't use callback, you can call the listen method as below. +```dart + // if you use socket communication and TCP. + final Communicator communicator = Tcp(); + final Camel receiver = Camel(communicator); + + // call listen method with a bind connection point. + await for( + CommunicateData data in receiver.listen( + SocketConnectionPoint(address: "127.0.0.1", port: 50000) + ) + ){ + print(data.message.body); // display received data. + } +``` + +When the receiver receives the custom command, then call the execute method of the command as below. +```dart + class MyCommand implements Command { + @override String get command => "MY_COMMAND"; + + @override + void execute(Uint8List data){ + // This method is called when data is received by the Camel.listen method. + print("received: ${utf8.decode(data)}"); // display "received: " + received data + } + } + + // if you use socket communication and TCP. + final Communicator communicator = Tcp(); + final Camel receiver = Camel(communicator); + CommandFactory.registerCommand(MyCommand()); // register command. + + // call listen method with a bind connection point. + await for( + CommunicateData _ in receiver.listen( + SocketConnectionPoint(address: "127.0.0.1", port: 50000) + ) + ){} +``` -TODO: Tell users more about the package: where to find more information, how to -contribute to the package, how to file issues, what response they can expect -from the package authors, and more. diff --git a/android/local.properties b/android/local.properties new file mode 100644 index 0000000..1a02ba0 --- /dev/null +++ b/android/local.properties @@ -0,0 +1,2 @@ +sdk.dir=C:\\Users\\R.NOTO\\AppData\\Local\\Android\\sdk +flutter.sdk=C:\\Users\\R.NOTO\\fvm\\versions\\3.10.3 \ No newline at end of file diff --git a/doc/README.jp.md b/doc/README.jp.md new file mode 100644 index 0000000..fc7b401 --- /dev/null +++ b/doc/README.jp.md @@ -0,0 +1,102 @@ +# Camel +[English](../README.md)
+ +ローカルネットワークで通信を行うためのFlutterパッケージ。 + +## 特徴 +このライブラリは"dart:io"ライブラリを使わず、簡単にローカルネットワーク通信を行えます。 +また、受信データはコールバックかStreamを使用した形式か選択して使用することができます。 + +## インストール +このパッケージをpubspec.yamlに追加してください。 +```yaml +# pubspec.yaml + +dependencies: + camel: ^ +``` + +## 使用方法 + +### 送信側 +受信側がCommandクラスのコールバック処理を使用しない場合は、以下のように送信処理を作成できます。 +```dart + // TCPを使用したSocket通信を行う場合。 + final Communicator communicator = Tcp(); + final Camel sender = Camel(communicator); + + // コネクションポイントと送信データを渡してsendメソッドを呼び出しします。 + sender.send( + SocketConnectionPoint(address: "127.0.0.1", port: 50000), + Message.fromBody(command: "dummy", body: "Hello, Camel."), + ); +``` + +受信側がCommandクラスのコールバック処理を使用する場合は、以下のようにします。 +```dart + class MyCommand implements Command { + @override String get command => "MY_COMMAND"; + + @override + void execute(Uint8List data){ + // このメソッドは受信側がデータを受信したときに呼び出されます。 + print("received: ${utf8.decode(data)}"); // received: Hello, Camel. + } + } + + // TCPを使用したSocket通信を行う場合。 + final Communicator communicator = Tcp(); + final Camel sender = Camel(communicator); + CommandFactory.registerCommand(MyCommand()); // 作成したコマンドの登録 + + // コネクションポイントと送信データを渡してsendメソッドを呼び出しします。 + // この時、作成したコマンドの名前をcommand引数に渡します。 + sender.send( + SocketConnectionPoint(address: "127.0.0.1", port: 50000), + Message.fromBody(command: "MY_COMMAND", body: "Hello, Camel."), + ); +``` + +### 受信側 +受信側がCommandクラスのコールバック処理を使用しない場合は、以下のように受信処理を作成できます。 +```dart + // TCPを使用したSocket通信を行う場合。 + final Communicator communicator = Tcp(); + final Camel receiver = Camel(communicator); + + // バインドするコネクションポイントとともにlistenメソッドを呼び出します。 + await for( + CommunicateData data in receiver.listen( + SocketConnectionPoint(address: "127.0.0.1", port: 50000) + ) + ){ + print(data.message.body); // Streamとしてデータを受信します。 + } +``` + + +受信側がCommandクラスのコールバック処理を使用する場合は、以下のようにします。 + +```dart + class MyCommand implements Command { + @override String get command => "MY_COMMAND"; + + @override + void execute(Uint8List data){ + // このメソッドは受信側がデータを受信したときに呼び出されます。 + print("received: ${utf8.decode(data)}"); + } + } + + // TCPを使用したSocket通信を行う場合。 + final Communicator communicator = Tcp(); + final Camel receiver = Camel(communicator); + + // バインドするコネクションポイントとともにlistenメソッドを呼び出します。 + await for( + CommunicateData _ in receiver.listen( + SocketConnectionPoint(address: "127.0.0.1", port: 50000) + ) + ){} +``` + diff --git a/exsample/analysis_options.yaml b/exsample/analysis_options.yaml index 61b6c4d..fd611ab 100644 --- a/exsample/analysis_options.yaml +++ b/exsample/analysis_options.yaml @@ -9,6 +9,10 @@ # packages, and plugins designed to encourage good coding practices. include: package:flutter_lints/flutter.yaml +analyzer: + exclude: + - test/*.mock.dart + linter: # The lint rules applied to this project can be customized in the # section below to disable rules from the `package:flutter_lints/flutter.yaml` diff --git a/exsample/android/build.gradle b/exsample/android/build.gradle index 58a8c74..713d7f6 100644 --- a/exsample/android/build.gradle +++ b/exsample/android/build.gradle @@ -26,6 +26,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/exsample/lib/main.dart b/exsample/lib/main.dart index 008fa38..7ec57ee 100644 --- a/exsample/lib/main.dart +++ b/exsample/lib/main.dart @@ -1,4 +1,9 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + import 'package:flutter/material.dart'; +import 'package:camel/camel.dart'; void main() { runApp(const MyApp()); @@ -7,108 +12,195 @@ void main() { class MyApp extends StatelessWidget { const MyApp({super.key}); - // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', + title: 'Camel Demo', theme: ThemeData( - // This is the theme of your application. - // - // Try running your application with "flutter run". You'll see the - // application has a blue toolbar. Then, without quitting the app, try - // changing the primarySwatch below to Colors.green and then invoke - // "hot reload" (press "r" in the console where you ran "flutter run", - // or simply save your changes to "hot reload" in a Flutter IDE). - // Notice that the counter didn't reset back to zero; the application - // is not restarted. primarySwatch: Colors.blue, ), - home: const MyHomePage(title: 'Flutter Demo Home Page'), + home: const NoCommandPage(title: 'Camel Demo Page(no use command)'), + // home: const CommandPage(title: 'Camel Demo Page(use command)'), ); } } -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); +class NoCommandPage extends StatefulWidget { + const NoCommandPage({super.key, required this.title}); + + final String title; + + @override + State createState() => _NoCommandPage(); +} + +class _NoCommandPage extends State { + late final Camel _receiver; - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. + static const String myAddress = + "127.0.0.1"; // if you use android emulator, change to emulator's ip address (etc."10.0.2.16"). + static const int port = 50000; - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". + String _sendText = ""; + String _receiveText = ""; + + @override + void initState() { + _receiver = Camel(Tcp()); + listen(); + super.initState(); + } + + Future listen() async { + // call listen method for receive message. + await for (CommunicateData data in _receiver + .listen(SocketConnectionPoint(address: myAddress, port: port))) { + setState(() { + _receiveText = data.message.body; + }); + } + } + + void _send() { + final Camel sender = + Camel(Tcp()); + // call send method for send message. + sender.send( + SocketConnectionPoint(address: myAddress, port: port), + Message.fromBody( + command: "dummy", + body: + _sendText), // if you don't use command, a command arg is anything. + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Received message:', + style: Theme.of(context).textTheme.titleLarge, + ), + Text( + _receiveText, + style: Theme.of(context).textTheme.titleLarge, + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 24), + child: TextField( + onChanged: (String value) { + _sendText = value; + }, + ), + ) + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: _send, + tooltip: 'Send', + child: const Icon(Icons.send), + ), // This trailing comma makes auto-formatting nicer for build methods. + ); + } +} + +class CommandPage extends StatefulWidget { + const CommandPage({super.key, required this.title}); final String title; @override - State createState() => _MyHomePageState(); + State createState() => _CommandPage(); } -class _MyHomePageState extends State { - int _counter = 0; +class _CommandPage extends State implements Command { + late final Camel _receiver; + + static const String myAddress = + "127.0.0.1"; // if you use android emulator, change to emulator's ip address (etc."10.0.2.16"). + static const int port = 50000; - void _incrementCounter() { + String _sendText = ""; + String _receiveText = ""; + + @override + String get command => "MY_COMMAND"; + + @override + void execute(Uint8List data) { setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // _counter without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _counter++; + _receiveText = utf8.decode(data); }); } + @override + void initState() { + CommandFactory.registerCommand(this); // register command. + _receiver = Camel(Tcp()); + listen(); + super.initState(); + } + + Future listen() async { + // call listen method for receive message. + await for (CommunicateData _ in _receiver + .listen(SocketConnectionPoint(address: myAddress, port: port))) {} + } + + void _send() { + final Camel sender = + Camel(Tcp()); + // call send method for send message. + sender.send( + SocketConnectionPoint(address: myAddress, port: port), + Message.fromBody( + command: "MY_COMMAND", + body: + _sendText), // if you don't use command, a command arg is anything. + ); + } + @override Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. return Scaffold( appBar: AppBar( - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. title: Text(widget.title), ), body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Invoke "debug painting" (press "p" in the console, choose the - // "Toggle Debug Paint" action from the Flutter Inspector in Android - // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) - // to see the wireframe for each widget. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). mainAxisAlignment: MainAxisAlignment.center, children: [ - const Text( - 'You have pushed the button this many times:', + Text( + 'Received message:', + style: Theme.of(context).textTheme.titleLarge, ), Text( - '$_counter', - style: Theme.of(context).textTheme.headlineMedium, + _receiveText, + style: Theme.of(context).textTheme.titleLarge, ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 24), + child: TextField( + onChanged: (String value) { + _sendText = value; + }, + ), + ) ], ), ), floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.add), + onPressed: _send, + tooltip: 'Send', + child: const Icon(Icons.send), ), // This trailing comma makes auto-formatting nicer for build methods. ); } diff --git a/exsample/pubspec.lock b/exsample/pubspec.lock index b2cb69d..785b491 100644 --- a/exsample/pubspec.lock +++ b/exsample/pubspec.lock @@ -1,14 +1,38 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + url: "https://pub.dev" + source: hosted + version: "61.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + url: "https://pub.dev" + source: hosted + version: "5.13.0" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" async: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" boolean_selector: dependency: transitive description: @@ -17,14 +41,29 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + camel: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "0.0.1" characters: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 + url: "https://pub.dev" + source: hosted + version: "0.4.0" clock: dependency: transitive description: @@ -37,10 +76,34 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" + source: hosted + version: "1.17.1" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.0.0" cupertino_icons: dependency: "direct main" description: @@ -49,6 +112,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + dartdoc: + dependency: "direct dev" + description: + name: dartdoc + sha256: "1712fe73fdfb7d889252234ddd19c707cd3d7c255025521adc90759feb56adb1" + url: "https://pub.dev" + source: hosted + version: "6.2.2" fake_async: dependency: transitive description: @@ -57,6 +128,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" flutter: dependency: "direct main" description: flutter @@ -75,30 +154,62 @@ packages: description: flutter source: sdk version: "0.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + html: + dependency: transitive + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" js: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" lints: dependency: transitive description: name: lints - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + markdown: + dependency: transitive + description: + name: markdown + sha256: "8e332924094383133cee218b676871f42db2514f1f6ac617b6cf6152a7faab8e" + url: "https://pub.dev" + source: hosted + version: "7.1.0" matcher: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -111,18 +222,34 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "2.1.0" path: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "2.1.4" sky_engine: dependency: transitive description: flutter @@ -172,10 +299,18 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.dev" + source: hosted + version: "0.5.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "1.3.2" vector_math: dependency: transitive description: @@ -184,5 +319,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: - dart: ">=2.19.6 <3.0.0" + dart: ">=3.0.0 <4.0.0" + flutter: ">=1.17.0" diff --git a/exsample/pubspec.yaml b/exsample/pubspec.yaml index 5f7968c..383af80 100644 --- a/exsample/pubspec.yaml +++ b/exsample/pubspec.yaml @@ -31,6 +31,8 @@ dependencies: flutter: sdk: flutter + camel: + path: ../ # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. @@ -47,6 +49,8 @@ dev_dependencies: # rules and activating additional ones. flutter_lints: ^2.0.0 + dartdoc: + # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/exsample/test/widget_test.dart b/exsample/test/widget_test.dart deleted file mode 100644 index 437c6dd..0000000 --- a/exsample/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:exsample/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/ios/Flutter/Generated.xcconfig b/ios/Flutter/Generated.xcconfig new file mode 100644 index 0000000..7539189 --- /dev/null +++ b/ios/Flutter/Generated.xcconfig @@ -0,0 +1,14 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=D:\create\flutter\camel\.fvm\flutter_sdk +FLUTTER_APPLICATION_PATH=D:\create\flutter\camel +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_TARGET=lib\main.dart +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=0.0.1 +FLUTTER_BUILD_NUMBER=0.0.1 +EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 +EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh new file mode 100755 index 0000000..f2b0443 --- /dev/null +++ b/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=D:\create\flutter\camel\.fvm\flutter_sdk" +export "FLUTTER_APPLICATION_PATH=D:\create\flutter\camel" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=lib\main.dart" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=0.0.1" +export "FLUTTER_BUILD_NUMBER=0.0.1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/lib/camel.dart b/lib/camel.dart index d82f1f5..2aacb30 100644 --- a/lib/camel.dart +++ b/lib/camel.dart @@ -1,7 +1,34 @@ library camel; -/// A Calculator. -class Calculator { - /// Returns [value] plus 1. - int addOne(int value) => value + 1; +import "dart:async"; +import "dart:convert"; +import "dart:typed_data"; + +import "communicator.dart"; +import "command.dart"; +import "message.dart"; + +export "communicator.dart"; +export "command.dart"; +export "message.dart"; + +class Camel { + Camel(this.communicator); + final Communicator communicator; + + Future send(C to, Message message) async { + T connection = await communicator.connect(to); + return await communicator + .send(CommunicateData(connection: connection, message: message)); + } + + Stream> listen(C bind) async* { + await for (CommunicateData data in await communicator.listen(bind)) { + Command? command = CommandFactory.getCommand(data.message); + if (command != null) { + command.execute(Uint8List.fromList(utf8.encode(data.message.body))); + } + yield data; + } + } } diff --git a/lib/command.dart b/lib/command.dart new file mode 100644 index 0000000..532af26 --- /dev/null +++ b/lib/command.dart @@ -0,0 +1,61 @@ +import 'package:flutter/foundation.dart'; + +import 'message.dart'; + +/// command class is the interface communication class and application. +abstract class Command { + /// command is the identified what is the receive data. + String get command; + + /// this method is called with received data from the communication class. + void execute(Uint8List data); +} + +/// construct Command instance from the received Message data. +/// this class has message dictionary. +/// it could register and read from other class. +/// in default, that dictionary registered default command. +abstract class CommandFactory { + static final Map _commands = {}; + + static List get commandList { + return _commands.values.toList(); + } + + static Command? getCommand(Message receivedData) { + if (kDebugMode && isTest) { + return getCommandSpy; + } else { + for (Command command in _commands.values) { + // if match the command, return that command. + if (command.command == receivedData.header.command) { + return command; + } + } + return null; + } + } + + static void registerCommand(Command command) { + _commands[command.command] = command; + } + + static void clearCommands() { + _commands.clear(); + } + + // ↓↓↓↓↓↓↓↓↓↓ for test ↓↓↓↓↓↓↓↓↓↓ + static bool isTest = false; + static Command? getCommandSpy; + static void setupTest() { + isTest = true; + } + + static void teardownTest() { + isTest = false; + } + + static void setGetCommandSpy(Command? command) { + getCommandSpy = command; + } +} diff --git a/lib/communicator.dart b/lib/communicator.dart new file mode 100644 index 0000000..8b4e7ff --- /dev/null +++ b/lib/communicator.dart @@ -0,0 +1,20 @@ +import 'message.dart'; +export "tcp.dart"; + +class CommunicateData { + CommunicateData({required this.connection, required this.message}); + + final T connection; + final Message message; +} + +abstract class Communicator { + Future connect( + C connectionPoint); // connection then return connection object. + Future close(); // close connection. + Future send( + CommunicateData + data); // send message to the connection and return send size. + Future>> listen( + C bind); // listen connect and receive messages. +} diff --git a/lib/message.dart b/lib/message.dart new file mode 100644 index 0000000..9cae0fd --- /dev/null +++ b/lib/message.dart @@ -0,0 +1,184 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +/// header sections +/// +/// these sections represent meanings each of data in header. +enum Sections { + /// represent the command of the message. + command, + + /// represent the body size of the message. + bodySize, +} + +/// section strings in a message. +extension SectionsChars on Sections { + String get name { + switch (this) { + case Sections.command: + return 'COMMAND'; + case Sections.bodySize: + return 'BODY_SIZE'; + } + } +} + +/// a header class in message +/// +/// ## format +/// **\\n\[\=\\n...\]** +/// +/// **headerSize**: the size exclude the header size string itself and a char of LF after that strings of the header. +/// +/// **sectionName**: a name that describes represent the meaning of data written after the section name itself. +/// +/// **sectionData**: data of a section. +/// +/// ### example +/// this message header has a command section and a body size section. +/// it represent SEND command and has 1000byte body data. +/// (Body data is omitted) +/// ```dart +/// "28\nCOMMAND=SEND\nBODY_SIZE=1000\n..." +/// ``` +/// +class MessageHeader { + /// a delimiter string in a header. + static const String delimiter = "\n"; + + late final String command; + late final int bodySize; + + /// a header size exclude the header size section. + late final int headerSize; + + /// raw data of the header exclude the header size section. + late final String rawData; + + /// a content of the header exclude the header size section. + String get headContent => + "${Sections.command.name}=$command\n${Sections.bodySize.name}=$bodySize\n"; + + /// a content of the header all. + String get message => "$headerSize\n$headContent"; + + /// constructor from Uint8List(receive data). + MessageHeader(Uint8List data) { + String? header = parseHeaderSize(utf8.decode(data)); + + if (header == null) { + rawData = ""; + return; + } else { + rawData = header; + } + + command = parseHeaderSection(header, Sections.command.name) ?? ""; + bodySize = + int.parse(parseHeaderSection(header, Sections.bodySize.name) ?? "0"); + } + + /// constructor from params(send data). + MessageHeader.fromParam({ + required this.command, + required this.bodySize, + }) { + headerSize = + "${Sections.command.name}=$command\n${Sections.bodySize.name}=$bodySize\n" + .length; + } + + /// parse a section from all of header. + /// + /// parse and get section data in [header]. + /// [header] is all of the header string. + /// this function searches a section of [section] in [header], then parses and returns the found data. + /// section's format is
=. + String? parseHeaderSection(String header, String section) { + RegExpMatch? valueMatch = + RegExp('^$section=(.*?)\$', dotAll: true, multiLine: true) + .firstMatch(header); + return valueMatch?.group(1); + } + + /// parse header size of the received message. + /// + /// parse and set a header size from received message string [message]. + /// after that return a header string exclude the header size. + String? parseHeaderSize(String message) { + RegExpMatch? headerSizeMatch = + RegExp('^([0-9]+)(?:$delimiter(.*))?', dotAll: true) + .firstMatch(message); + final String? headerSizeStr = headerSizeMatch?.group(1); + + // check it was not match. + // check it is a number. + if ((headerSizeStr == null)) { + throw const MessageFormatException('Could not find body size.'); + } else { + headerSize = int.parse(headerSizeStr); + } + + try { + return headerSizeMatch?.group(2)?.substring(0, headerSize); + } on RangeError { + return headerSizeMatch?.group(2)?.substring(0); + } + } +} + +/// a message class +/// +/// ## format +/// **\\[\\]** +/// +/// **header**: the header include info of size etc in message.(reference [MessageHeader]) +/// **body**: a body data of message. +/// if the char count is more than [MessageHeader.bodySize], doesn't recognize more strings. +/// +/// ### example +/// this message has a body size section. +/// it define that a body size is 10byte, but body data has 27byte data. +/// then this class recognize only 10byte data. +/// ```dart +/// const data = "15\nBODY_SIZE=10\n hello, i have 27byte data."; +/// Message message = Message(Uint8List.fromList(utf8.encode(data))); +/// print(message.body); // " hello, i " +/// ``` +/// +class Message { + late final MessageHeader header; + late final String body; + String get message => "${header.message}$body"; + + /// constructor from Uint8List(receive data). + Message(Uint8List data) { + header = MessageHeader(data); + // body start position is the header size + the header size char count + LF + final int headerEndPosition = + header.headerSize + header.headerSize.toString().length + 1; + int bodyEndPosition = headerEndPosition + header.bodySize; + if (bodyEndPosition > data.length) { + bodyEndPosition = data.length; + } + body = utf8.decode(data.sublist(headerEndPosition, bodyEndPosition)); + } + + /// constructor from params(send data). + Message.fromBody({ + required String command, + required this.body, + }) { + header = MessageHeader.fromParam(command: command, bodySize: body.length); + } +} + +/// exception of format error. +class MessageFormatException implements Exception { + const MessageFormatException(this.message); + final String message; + + @override + String toString() => message; +} diff --git a/lib/tcp.dart b/lib/tcp.dart new file mode 100644 index 0000000..c53cc3f --- /dev/null +++ b/lib/tcp.dart @@ -0,0 +1,142 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/foundation.dart'; + +import 'communicator.dart'; +import 'message.dart'; + +class SocketConnectionPoint { + SocketConnectionPoint({ + required this.address, + required this.port, + }); + + final String address; + final int port; +} + +class CommunicateDataTcp { + CommunicateDataTcp({required this.connection, required this.dataSize}); + + void receive(Uint8List data) { + final newBuffer = Uint8List(_receiveBuffer.length + data.length); + newBuffer.setAll(0, _receiveBuffer); + newBuffer.setAll(_receiveBuffer.length, data); + _receiveBuffer = newBuffer; + } + + bool isReceivedAll() { + return _receiveBuffer.length >= dataSize; + } + + CommunicateData? get receiveData { + if (!isReceivedAll()) return null; + + return CommunicateData( + connection: connection, message: Message(_receiveBuffer)); + } + + Uint8List _receiveBuffer = Uint8List(0); + final Socket connection; + final int dataSize; +} + +class Tcp implements Communicator { + final Map _receiveBuffers = {}; + + @override + Future connect(SocketConnectionPoint connectionPoint) async { + return await _connect(connectionPoint.address, connectionPoint.port); + } + + @override + Future close() async {} + + @override + Future send(CommunicateData data) async { + data.connection + .write("${data.message.message.length}\n${data.message.message}"); + return Future(() => data.message.message.length); + } + + @override + Future>> listen( + SocketConnectionPoint bind) async { + final StreamController> controller = + StreamController(); + ServerSocket serverSocket = await _bind(bind.address, bind.port); + // connection + serverSocket.listen((Socket socket) { + // receive data + socket.listen((Uint8List data) { + // if have not received data yet. + if (_receiveBuffers[socket] == null) { + int bodyPosition = 0; + int dataSize = 0; + // search first LF sign. + // chars until first LF represent the size of this message. + for (int i = 0; i < data.length; i++) { + if (data[i] == utf8.encode("\n").first) { + bodyPosition = i + 1; // the message after first LF. + dataSize = int.parse(utf8.decode(data.sublist(0, i))); + break; + } + } + + data = data.sublist(bodyPosition); // change [data] to only the body. + + _receiveBuffers[socket] = + CommunicateDataTcp(connection: socket, dataSize: dataSize); + } + + final receiveBuffer = _receiveBuffers[socket]; + if (receiveBuffer == null) return; + + receiveBuffer.receive(data); + + // if received all of messages. + if (receiveBuffer.isReceivedAll()) { + controller.sink.add(receiveBuffer.receiveData!); // stream data. + _receiveBuffers.remove(receiveBuffer.connection); // remove buffer. + } + }); + }); + return controller.stream; + } + + // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓ for test ↓↓↓↓↓↓↓↓↓↓↓↓↓↓ + Function(dynamic address, int port, + {dynamic sourceAddress, + int sourcePort, + Duration? timeout}) _connect = Socket.connect; + Function( + dynamic address, + int port, { + int backlog, + bool v6Only, + bool shared, + }) _bind = ServerSocket.bind; + + void setConnectMock( + Function(dynamic, int, + {dynamic sourceAddress, int sourcePort, Duration? timeout}) + connect) { + if (kDebugMode) { + _connect = connect; + } + } + + void setBindMock( + Function( + dynamic address, + int port, { + int backlog, + bool v6Only, + bool shared, + }) bind) { + if (kDebugMode) { + _bind = bind; + } + } +} diff --git a/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig index 201720c..516c332 100644 --- a/macos/Flutter/ephemeral/Flutter-Generated.xcconfig +++ b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig @@ -1,6 +1,6 @@ // This is a generated file; do not edit or check into version control. -FLUTTER_ROOT=/Users/ta4/flutter -FLUTTER_APPLICATION_PATH=/Users/ta4/projects/flutter/camel +FLUTTER_ROOT=D:\create\flutter\camel\.fvm\flutter_sdk +FLUTTER_APPLICATION_PATH=D:\create\flutter\camel COCOAPODS_PARALLEL_CODE_SIGN=true FLUTTER_BUILD_DIR=build FLUTTER_BUILD_NAME=0.0.1 diff --git a/macos/Flutter/ephemeral/flutter_export_environment.sh b/macos/Flutter/ephemeral/flutter_export_environment.sh index 522f129..9f21585 100755 --- a/macos/Flutter/ephemeral/flutter_export_environment.sh +++ b/macos/Flutter/ephemeral/flutter_export_environment.sh @@ -1,7 +1,7 @@ #!/bin/sh # This is a generated file; do not edit or check into version control. -export "FLUTTER_ROOT=/Users/ta4/flutter" -export "FLUTTER_APPLICATION_PATH=/Users/ta4/projects/flutter/camel" +export "FLUTTER_ROOT=D:\create\flutter\camel\.fvm\flutter_sdk" +export "FLUTTER_APPLICATION_PATH=D:\create\flutter\camel" export "COCOAPODS_PARALLEL_CODE_SIGN=true" export "FLUTTER_BUILD_DIR=build" export "FLUTTER_BUILD_NAME=0.0.1" diff --git a/pubspec.yaml b/pubspec.yaml index 28627fe..92c979e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,10 +1,10 @@ name: camel -description: A new Flutter package project. -version: 0.0.1 +description: A Flutter package for communicating in a local network. +version: 1.1.0 homepage: environment: - sdk: '>=2.19.6 <3.0.0' + sdk: '>=2.18.0 <4.0.0' flutter: ">=1.17.0" dependencies: @@ -15,6 +15,8 @@ dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 + mockito: ^5.4.0 + build_runner: ^2.3.3 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/test/camel_test.dart b/test/camel_test.dart index 331270e..8feb726 100644 --- a/test/camel_test.dart +++ b/test/camel_test.dart @@ -1,12 +1,54 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:camel/camel.dart'; void main() { - test('adds one to input values', () { - final calculator = Calculator(); - expect(calculator.addOne(2), 3); - expect(calculator.addOne(-7), -6); - expect(calculator.addOne(0), 1); + useTcpTest(); +} + +class CommandStub implements Command { + @override + String get command => "STUB"; + static Uint8List? receiveSpy; + static bool isCalledExecute = false; + + @override + void execute(Uint8List data) { + isCalledExecute = true; + receiveSpy = data; + } +} + +void useTcpTest() { + group("TCP", () { + test("should be communicate", () async { + Tcp tcpSend = Tcp(); + Camel camelSend = Camel(tcpSend); + + Tcp tcpReceive = Tcp(); + Camel camelReceive = Camel(tcpReceive); + + CommandFactory.registerCommand(CommandStub()); + + Stream> stream = camelReceive + .listen(SocketConnectionPoint(address: "127.0.0.1", port: 15000)); + + camelSend.send( + SocketConnectionPoint(address: "127.0.0.1", port: 15000), + Message.fromBody( + command: CommandStub().command, body: "Hello, camel")); + + await for (CommunicateData _ in stream) { + break; + } + + expect(CommandStub.isCalledExecute, isTrue); + expect(utf8.decode(CommandStub.receiveSpy!), "Hello, camel"); + }, tags: "UseNetwork"); }); } diff --git a/test/command_test.dart b/test/command_test.dart new file mode 100644 index 0000000..2213b80 --- /dev/null +++ b/test/command_test.dart @@ -0,0 +1,154 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:mockito/annotations.dart'; + +import 'command_test.mocks.dart'; +import 'package:camel/camel.dart'; + +@GenerateMocks([Message]) +@GenerateMocks([MessageHeader]) +void main() { + setUp(() async { + CommandFactory.clearCommands(); + }); + commandFactoryTest(); +} + +class CommandStub implements Command { + CommandStub({ + required this.command, + }); + + @override + final String command; + @override + void execute(Uint8List data) {} +} + +MockMessage constructMessageMock({ + MessageHeader? header, + String? body, + String? command, + int? bodySize, +}) { + // if header does not set. + if (header == null) { + // construct header mock. + header = MockMessageHeader(); + when(header.command).thenAnswer((realInvocation) { + return command ??= ""; + }); + when(header.bodySize).thenAnswer((realInvocation) { + return bodySize ??= 0; + }); + } + + // construct message mock. + MockMessage mockMessage = MockMessage(); + when(mockMessage.header).thenAnswer((realInvocation) { + return header!; + }); + + when(mockMessage.body).thenAnswer((realInvocation) { + return body ?? ""; + }); + + return mockMessage; +} + +bool isInCommandList(Command command, List commandList) { + bool result = false; + for (Command c in commandList) { + if (command == c) { + result = true; + break; + } + } + return result; +} + +Uint8List convertUint8data(String message) { + return Uint8List.fromList(utf8.encode(message)); +} + +void expectUint8List(Uint8List exp, Uint8List actual) { + try { + expect(exp.length, actual.length); + for (int i = 0; i < exp.length; i++) { + expect(exp[i], actual[i]); + } + } catch (e) { + fail("two lists are difference.\n expect: $exp\n actual: $actual"); + } +} + +void commandFactoryTest() { + group('register command', () { + test('should be return null if command no register', () { + MockMessage mockMessage = constructMessageMock(command: ""); + Command? command = CommandFactory.getCommand(mockMessage); + expect(command, null); + }); + + test('should be return Command Stub if command registered', () { + CommandStub commandStub = CommandStub(command: "A"); + CommandFactory.registerCommand(commandStub); // register command. + + MockMessage mockMessage = constructMessageMock(command: "A"); + Command? command = CommandFactory.getCommand(mockMessage); + expect(command, commandStub); + }); + + test('should be return null if no match command in registered', () { + CommandStub commandStub = CommandStub(command: "A"); + CommandFactory.registerCommand(commandStub); // register command. + + MockMessage mockMessage = constructMessageMock(command: "B"); + Command? command = CommandFactory.getCommand(mockMessage); + expect(command, null); + }); + + test( + 'should be return the Command registered after if commands register two times', + () { + CommandStub commandStubFirst = CommandStub(command: "A"); + CommandFactory.registerCommand( + commandStubFirst); // register command first. + CommandStub commandStubSecond = CommandStub(command: "A"); + CommandFactory.registerCommand( + commandStubSecond); // register same command second. + + MockMessage mockMessage = constructMessageMock(command: "A"); + Command? command = CommandFactory.getCommand(mockMessage); + expect(command, commandStubSecond); + }); + }); + + group('get command list', () { + test('should be get empty list when register no command', () { + expect(CommandFactory.commandList.length, 0); + }); + + test('should be get one content list when register one command', () { + CommandStub commandStub = CommandStub(command: "A"); + CommandFactory.registerCommand(commandStub); + expect(CommandFactory.commandList.length, 1); + expect(CommandFactory.commandList[0], commandStub); + }); + + test('should be get two content list when register two command', () { + CommandStub commandStub1 = CommandStub(command: "A"); + CommandFactory.registerCommand(commandStub1); + CommandStub commandStub2 = CommandStub(command: "B"); + CommandFactory.registerCommand(commandStub2); + + List commandList = CommandFactory.commandList; + expect(commandList.length, 2); + expect(isInCommandList(commandStub1, commandList), isTrue); + expect(isInCommandList(commandStub2, commandList), isTrue); + }); + }); +} diff --git a/test/command_test.mocks.dart b/test/command_test.mocks.dart new file mode 100644 index 0000000..98d8536 --- /dev/null +++ b/test/command_test.mocks.dart @@ -0,0 +1,161 @@ +// Mocks generated by Mockito 5.4.2 from annotations +// in camel/test/command_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:camel/message.dart' as _i2; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeMessageHeader_0 extends _i1.SmartFake implements _i2.MessageHeader { + _FakeMessageHeader_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [Message]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockMessage extends _i1.Mock implements _i2.Message { + MockMessage() { + _i1.throwOnMissingStub(this); + } + + @override + _i2.MessageHeader get header => (super.noSuchMethod( + Invocation.getter(#header), + returnValue: _FakeMessageHeader_0( + this, + Invocation.getter(#header), + ), + ) as _i2.MessageHeader); + @override + set header(_i2.MessageHeader? _header) => super.noSuchMethod( + Invocation.setter( + #header, + _header, + ), + returnValueForMissingStub: null, + ); + @override + String get body => (super.noSuchMethod( + Invocation.getter(#body), + returnValue: '', + ) as String); + @override + set body(String? _body) => super.noSuchMethod( + Invocation.setter( + #body, + _body, + ), + returnValueForMissingStub: null, + ); + @override + String get message => (super.noSuchMethod( + Invocation.getter(#message), + returnValue: '', + ) as String); +} + +/// A class which mocks [MessageHeader]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockMessageHeader extends _i1.Mock implements _i2.MessageHeader { + MockMessageHeader() { + _i1.throwOnMissingStub(this); + } + + @override + String get command => (super.noSuchMethod( + Invocation.getter(#command), + returnValue: '', + ) as String); + @override + set command(String? _command) => super.noSuchMethod( + Invocation.setter( + #command, + _command, + ), + returnValueForMissingStub: null, + ); + @override + int get bodySize => (super.noSuchMethod( + Invocation.getter(#bodySize), + returnValue: 0, + ) as int); + @override + set bodySize(int? _bodySize) => super.noSuchMethod( + Invocation.setter( + #bodySize, + _bodySize, + ), + returnValueForMissingStub: null, + ); + @override + int get headerSize => (super.noSuchMethod( + Invocation.getter(#headerSize), + returnValue: 0, + ) as int); + @override + set headerSize(int? _headerSize) => super.noSuchMethod( + Invocation.setter( + #headerSize, + _headerSize, + ), + returnValueForMissingStub: null, + ); + @override + String get rawData => (super.noSuchMethod( + Invocation.getter(#rawData), + returnValue: '', + ) as String); + @override + set rawData(String? _rawData) => super.noSuchMethod( + Invocation.setter( + #rawData, + _rawData, + ), + returnValueForMissingStub: null, + ); + @override + String get headContent => (super.noSuchMethod( + Invocation.getter(#headContent), + returnValue: '', + ) as String); + @override + String get message => (super.noSuchMethod( + Invocation.getter(#message), + returnValue: '', + ) as String); + @override + String? parseHeaderSection( + String? header, + String? section, + ) => + (super.noSuchMethod(Invocation.method( + #parseHeaderSection, + [ + header, + section, + ], + )) as String?); + @override + String? parseHeaderSize(String? src) => (super.noSuchMethod(Invocation.method( + #parseHeaderSize, + [src], + )) as String?); +} diff --git a/test/message_test.dart b/test/message_test.dart new file mode 100644 index 0000000..2995740 --- /dev/null +++ b/test/message_test.dart @@ -0,0 +1,296 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:mockito/annotations.dart'; + +import 'message_test.mocks.dart'; +import 'package:camel/camel.dart'; + +@GenerateMocks([Message]) +@GenerateMocks([MessageHeader]) +void main() { + setUp(() async {}); + messageHeaderTest(); + messageFormatTest(); + messageConstructFromSendTest(); + convertBinDataTest(); +} + +MockMessage constructMessageMock({ + MessageHeader? header, + String? body, + String? command, + int? bodySize, +}) { + // if header does not set. + if (header == null) { + // construct header mock. + header = MockMessageHeader(); + when(header.command).thenAnswer((realInvocation) { + return command ??= ""; + }); + when(header.bodySize).thenAnswer((realInvocation) { + return bodySize ??= 0; + }); + } + + // construct message mock. + MockMessage mockMessage = MockMessage(); + when(mockMessage.header).thenAnswer((realInvocation) { + return header!; + }); + + when(mockMessage.body).thenAnswer((realInvocation) { + return body ?? ""; + }); + + return mockMessage; +} + +Uint8List convertUint8data(String message) { + return Uint8List.fromList(utf8.encode(message)); +} + +void expectUint8List(Uint8List exp, Uint8List actual) { + try { + expect(exp.length, actual.length); + for (int i = 0; i < exp.length; i++) { + expect(exp[i], actual[i]); + } + } catch (e) { + fail("two lists are difference.\n expect: $exp\n actual: $actual"); + } +} + +void messageHeaderTest() { + group("parse test", () { + group('get header size', () { + test('should be throw MessageFormatException if arg is empty header', () { + expect(() => MessageHeader(convertUint8data("")), + throwsA(const TypeMatcher())); + }); + + test( + 'should be throw MessageFormatException if arg is that is not number.', + () { + expect(() => MessageHeader(convertUint8data("a")), + throwsA(const TypeMatcher())); + }); + + test( + 'should be throw MessageFormatException if get arg is start from LF.', + () { + expect(() => MessageHeader(convertUint8data("\n100")), + throwsA(const TypeMatcher())); + }); + + test('should be get 0 as the header size if get arg is 0.', () { + expect(MessageHeader(convertUint8data("0")).headerSize, 0); + }); + + test('should be get 100 as the header size if get arg is 100.', () { + expect(MessageHeader(convertUint8data("100")).headerSize, 100); + }); + + test('should be get 100 as the header size if get arg is 100+LF.', () { + expect(MessageHeader(convertUint8data("100\n")).headerSize, 100); + }); + }); + + group('get commands', () { + test('should be get no command if there is not COMMAND header.', () { + MessageHeader header = MessageHeader(convertUint8data("100\n")); + expect(header.command, ""); + }); + + test('should be get a command if there is COMMAND header.', () { + MessageHeader header = + MessageHeader(convertUint8data("15\nCOMMAND=command")); + expect(header.command, "command"); + }); + + test('should be get a command in the middle if the header size is less.', + () { + MessageHeader header = + MessageHeader(convertUint8data("14\nCOMMAND=command")); + expect(header.command, "comman"); + }); + + test('should be get no command if the header size is less.', () { + MessageHeader header = + MessageHeader(convertUint8data("0\nCOMMAND=command")); + expect(header.command, ""); + }); + + test('should be get an before command if the COMMAND section is twice.', + () { + MessageHeader header = MessageHeader( + convertUint8data("34\nCOMMAND=command1\nCOMMAND=command2")); + expect(header.command, "command1"); + }); + }); + + group('get body size', () { + test('should be get 0 as body size if there is not BODY_SIZE header.', + () { + MessageHeader header = MessageHeader(convertUint8data("100\n")); + expect(header.bodySize, 0); + }); + + test('should be get 10 as body size if there is BODY_SIZE header.', () { + MessageHeader header = + MessageHeader(convertUint8data("12\nBODY_SIZE=10")); + expect(header.bodySize, 10); + }); + + test( + 'should be get 1 as body size(in the middle) if the header size is less.', + () { + MessageHeader header = + MessageHeader(convertUint8data("11\nBODY_SIZE=10")); + expect(header.bodySize, 1); + }); + + test('should be get 0 as body size if the header size is less.', () { + MessageHeader header = + MessageHeader(convertUint8data("0\nBODY_SIZE=10")); + expect(header.bodySize, 0); + }); + + test( + 'should be get an before body size if the BODY_SIZE section is twice.', + () { + MessageHeader header = + MessageHeader(convertUint8data("24\nBODY_SIZE=1\nBODY_SIZE=2")); + expect(header.bodySize, 1); + }); + }); + + group('get raw data', () { + test('should be not get raw data if the header size is 0.', () { + MessageHeader header = MessageHeader(convertUint8data("0\n")); + expect(header.rawData, ""); + }); + + test( + 'should be not get raw data if the header size is 0 and exist header data.', + () { + MessageHeader header = MessageHeader(convertUint8data("0\ndata")); + expect(header.rawData, ""); + }); + + test('should be get raw data if exist header data.', () { + MessageHeader header = MessageHeader(convertUint8data("4\ndata")); + expect(header.rawData, "data"); + }); + + test('should be get raw data in the middle if header size is less.', () { + MessageHeader header = MessageHeader(convertUint8data("3\ndata")); + expect(header.rawData, "dat"); + }); + }); + + group('get header some pattern', () { + test('should be get variable data.', () { + MessageHeader header = MessageHeader(convertUint8data( + "33\nCOMMAND=someCommand\nBODY_SIZE=10\nAAAAAAAAAA")); + expect(header.headerSize, 33); + expect(header.rawData, "COMMAND=someCommand\nBODY_SIZE=10\n"); + expect(header.bodySize, 10); + expect(header.command, "someCommand"); + }); + }); + }); +} + +void messageFormatTest() { + group('header', () { + test('should be get header data.', () { + Message message = Message(convertUint8data( + "33\nCOMMAND=someCommand\nBODY_SIZE=10\nAAAAAAAAAA")); + expect(message.header.headerSize, 33); + expect(message.header.rawData, "COMMAND=someCommand\nBODY_SIZE=10\n"); + expect(message.header.bodySize, 10); + expect(message.header.command, "someCommand"); + }); + }); + + group('body', () { + test('should be get body data.', () { + Message message = Message(convertUint8data( + "33\nCOMMAND=someCommand\nBODY_SIZE=10\nAAAAAAAAAA")); + expect("AAAAAAAAAA", message.body); + }); + + test('should be get body data in the middle if the body size is less.', () { + Message message = Message( + convertUint8data("33\nCOMMAND=someCommand\nBODY_SIZE=8\nAAAAAAAAAA")); + expect("AAAAAAAA", message.body); + }); + + test('should be get body data all if the body size is more.', () { + Message message = Message(convertUint8data( + "33\nCOMMAND=someCommand\nBODY_SIZE=15\nAAAAAAAAAA")); + expect("AAAAAAAAAA", message.body); + }); + }); +} + +Message constructMessageFromBody( + {required String command, required String body}) { + return Message.fromBody( + command: command, body: body); //Uint8List.fromList(utf8.encode(body))); +} + +void checkMessageCommandAndBody( + {required Message message, required String command, required String body}) { + expect(message.header.command, command); + expect(message.body, body); +} + +void messageConstructFromSendTest() { + group("constructor from sender", () { + test("should be construct message command and body", () { + Message message = constructMessageFromBody(command: "", body: ""); + checkMessageCommandAndBody(message: message, command: "", body: ""); + }); + + test( + "should be return command and body when construct message command and body", + () { + Message message = constructMessageFromBody(command: "AAA", body: "data"); + checkMessageCommandAndBody( + message: message, command: "AAA", body: "data"); + }); + + test("should be return 4byte as body size when construct message with aaaa", + () { + Message message = constructMessageFromBody(command: "", body: "aaaa"); + expect(message.header.bodySize, 4); + }); + + test("should be get the header size", () { + Message message = + constructMessageFromBody(command: "AAAAA", body: "aaaa"); + // COMMAND=AAAAA\n + // BODY_SIZE=4\n + // -> 26byte + expect(message.header.headerSize, 26); + }); + }); +} + +void convertBinDataTest() { + group("convert bin data", () { + test("should be convert to uint8list", () { + Message message = + constructMessageFromBody(command: "AAAAA", body: "aaaa"); + Message receive = + Message(Uint8List.fromList(utf8.encode(message.message))); + expect(receive.header.command, "AAAAA"); + expect(receive.body, "aaaa"); + }); + }); +} diff --git a/test/message_test.mocks.dart b/test/message_test.mocks.dart new file mode 100644 index 0000000..053c06d --- /dev/null +++ b/test/message_test.mocks.dart @@ -0,0 +1,161 @@ +// Mocks generated by Mockito 5.4.2 from annotations +// in camel/test/message_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:camel/message.dart' as _i2; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeMessageHeader_0 extends _i1.SmartFake implements _i2.MessageHeader { + _FakeMessageHeader_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [Message]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockMessage extends _i1.Mock implements _i2.Message { + MockMessage() { + _i1.throwOnMissingStub(this); + } + + @override + _i2.MessageHeader get header => (super.noSuchMethod( + Invocation.getter(#header), + returnValue: _FakeMessageHeader_0( + this, + Invocation.getter(#header), + ), + ) as _i2.MessageHeader); + @override + set header(_i2.MessageHeader? _header) => super.noSuchMethod( + Invocation.setter( + #header, + _header, + ), + returnValueForMissingStub: null, + ); + @override + String get body => (super.noSuchMethod( + Invocation.getter(#body), + returnValue: '', + ) as String); + @override + set body(String? _body) => super.noSuchMethod( + Invocation.setter( + #body, + _body, + ), + returnValueForMissingStub: null, + ); + @override + String get message => (super.noSuchMethod( + Invocation.getter(#message), + returnValue: '', + ) as String); +} + +/// A class which mocks [MessageHeader]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockMessageHeader extends _i1.Mock implements _i2.MessageHeader { + MockMessageHeader() { + _i1.throwOnMissingStub(this); + } + + @override + String get command => (super.noSuchMethod( + Invocation.getter(#command), + returnValue: '', + ) as String); + @override + set command(String? _command) => super.noSuchMethod( + Invocation.setter( + #command, + _command, + ), + returnValueForMissingStub: null, + ); + @override + int get bodySize => (super.noSuchMethod( + Invocation.getter(#bodySize), + returnValue: 0, + ) as int); + @override + set bodySize(int? _bodySize) => super.noSuchMethod( + Invocation.setter( + #bodySize, + _bodySize, + ), + returnValueForMissingStub: null, + ); + @override + int get headerSize => (super.noSuchMethod( + Invocation.getter(#headerSize), + returnValue: 0, + ) as int); + @override + set headerSize(int? _headerSize) => super.noSuchMethod( + Invocation.setter( + #headerSize, + _headerSize, + ), + returnValueForMissingStub: null, + ); + @override + String get rawData => (super.noSuchMethod( + Invocation.getter(#rawData), + returnValue: '', + ) as String); + @override + set rawData(String? _rawData) => super.noSuchMethod( + Invocation.setter( + #rawData, + _rawData, + ), + returnValueForMissingStub: null, + ); + @override + String get headContent => (super.noSuchMethod( + Invocation.getter(#headContent), + returnValue: '', + ) as String); + @override + String get message => (super.noSuchMethod( + Invocation.getter(#message), + returnValue: '', + ) as String); + @override + String? parseHeaderSection( + String? header, + String? section, + ) => + (super.noSuchMethod(Invocation.method( + #parseHeaderSection, + [ + header, + section, + ], + )) as String?); + @override + String? parseHeaderSize(String? src) => (super.noSuchMethod(Invocation.method( + #parseHeaderSize, + [src], + )) as String?); +} diff --git a/test/tcp_test.dart b/test/tcp_test.dart new file mode 100644 index 0000000..821819c --- /dev/null +++ b/test/tcp_test.dart @@ -0,0 +1,259 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:mockito/annotations.dart'; +import 'tcp_test.mocks.dart'; + +import "package:camel/camel.dart"; +import 'command_test.dart'; + +typedef ConnectFunc = Function(dynamic address, int port, + {dynamic sourceAddress, int sourcePort, Duration? timeout}); +typedef BindFunc = Function( + dynamic address, + int port, { + int backlog, + bool v6Only, + bool shared, +}); + +@GenerateMocks([Socket]) +@GenerateMocks([ServerSocket]) +@GenerateMocks([Message]) +@GenerateMocks([CommandFactory]) +@GenerateMocks([Command]) +void main() { + useLibraryTest(); +} + +class ConnectSpy { + ConnectSpy({required this.tcp, required this.socket}); + String? connectAddress; + int? connectPort; + final Tcp tcp; + final MockSocket socket; +} + +class ListenSpy { + ListenSpy( + {required this.tcp, required this.socket, required this.serverSocket}); + String? bindAddress; + int? bindPort; + final Tcp tcp; + final MockSocket socket; + final MockServerSocket serverSocket; + void Function(Uint8List)? receiveCallback; +} + +Future connectWithMock({ + String address = "127.0.0.1", + int port = 0, + MockSocket? mockSocket, +}) async { + Tcp tcp = Tcp(); + ConnectSpy spy = ConnectSpy(tcp: tcp, socket: mockSocket ?? MockSocket()); + + Future connectMock(dynamic address, int port, + {dynamic sourceAddress, int sourcePort = 0, Duration? timeout}) async { + spy.connectAddress = address; + spy.connectPort = port; + return spy.socket; + } + + tcp.setConnectMock(connectMock); + await tcp.connect(SocketConnectionPoint(address: address, port: port)); + + return spy; +} + +Future bindMock({ + MockSocket? mockSocket, + MockServerSocket? mockServerSocket, +}) async { + Tcp tcp = Tcp(); + ListenSpy spy = ListenSpy( + tcp: tcp, + socket: mockSocket ?? MockSocket(), + serverSocket: mockServerSocket ?? MockServerSocket()); + + Future bindMock( + dynamic address, + int port, { + int backlog = 0, + bool v6Only = false, + bool shared = false, + }) async { + spy.bindAddress = address; + spy.bindPort = port; + return spy.serverSocket; + } + + tcp.setBindMock(bindMock); + + return spy; +} + +void constructListenMock(ListenSpy spy, List receiveData) { + when(spy.serverSocket.listen(any)).thenAnswer((Invocation invocation) { + final void Function(Socket) connectCallback = + invocation.positionalArguments[0]; + constructSocketMock(spy, receiveData); + connectCallback(spy.socket); // connection + verify(spy.socket.listen(any)); + return StreamSubscriptionStub(); + }); +} + +void constructSocketMock(ListenSpy spy, List receiveData) { + // socket.listen spy + when(spy.socket.listen(any)).thenAnswer((Invocation invocation) { + final void Function(Uint8List) receiveCallback = + invocation.positionalArguments[0]; + spy.receiveCallback = receiveCallback; + + // call as many times as receiveData. + for (String data in receiveData) { + receiveCallback(convertUint8data(data)); + } + return StreamSubscriptionStub(); + }); +} + +void useLibraryTest() { + group("connect", () { + test("should be hand over the IP address and the port number", () async { + ConnectSpy spy = await connectWithMock(address: "127.0.0.1", port: 1000); + + expect(spy.connectAddress, "127.0.0.1"); + expect(spy.connectPort, 1000); + }); + }); + + group("send", () { + test("should be write the empty message to the address handed over", + () async { + ConnectSpy spy = await connectWithMock(address: "127.0.0.1", port: 1000); + MockMessage mockMessage = MockMessage(); + when(mockMessage.message).thenReturn(""); + int sentByte = await spy.tcp + .send(CommunicateData(connection: spy.socket, message: mockMessage)); + + verify(spy.socket.write("0\n")); + expect(sentByte, 0); + }); + + test("should be write the message to the address handed over", () async { + ConnectSpy spy = await connectWithMock(address: "127.0.0.1", port: 1000); + MockMessage mockMessage = MockMessage(); + when(mockMessage.message).thenReturn("message"); + int sentByte = await spy.tcp + .send(CommunicateData(connection: spy.socket, message: mockMessage)); + + verify(spy.socket.write("7\nmessage")); + expect(sentByte, 7); + }); + }); + + group("send", () { + test("should be write the empty message to the address handed over", + () async { + ConnectSpy spy = await connectWithMock(address: "127.0.0.1", port: 1000); + MockMessage mockMessage = MockMessage(); + when(mockMessage.message).thenReturn(""); + int sentByte = await spy.tcp + .send(CommunicateData(connection: spy.socket, message: mockMessage)); + + verify(spy.socket.write("0\n")); + expect(sentByte, 0); + }); + + test("should be write the message to the address handed over", () async { + ConnectSpy spy = await connectWithMock(address: "127.0.0.1", port: 1000); + MockMessage mockMessage = MockMessage(); + when(mockMessage.message).thenReturn("message"); + int sentByte = await spy.tcp + .send(CommunicateData(connection: spy.socket, message: mockMessage)); + + verify(spy.socket.write("7\nmessage")); + expect(sentByte, 7); + }); + }); + + group("listen", () { + test("should be execute received message command", () async { + ListenSpy spy = await bindMock(); + + constructListenMock( + spy, ["39\n32\nCOMMAND=someCommand\nBODY_SIZE=4\nbody"]); + + await for (CommunicateData data in await spy.tcp + .listen(SocketConnectionPoint(address: "127.0.0.1", port: 1000))) { + expect(data.message.header.message, + "32\nCOMMAND=someCommand\nBODY_SIZE=4\n"); + expect(data.message.body, "body"); + expect(data.connection, spy.socket); + break; + } + + verify(spy.serverSocket.listen(any)); + expect(spy.bindAddress, "127.0.0.1"); + expect(spy.bindPort, 1000); + }); + + test("should be receive split data", () async { + ListenSpy spy = await bindMock(); + + constructListenMock( + spy, ["39\n32\nCOMMAND=someCommand", "\nBODY_SIZE=4\nbody"]); + + await for (CommunicateData data in await spy.tcp + .listen(SocketConnectionPoint(address: "127.0.0.1", port: 1000))) { + expect(data.message.header.message, + "32\nCOMMAND=someCommand\nBODY_SIZE=4\n"); + expect(data.message.body, "body"); + expect(data.connection, spy.socket); + break; + } + + verify(spy.serverSocket.listen(any)); + expect(spy.bindAddress, "127.0.0.1"); + expect(spy.bindPort, 1000); + }); + }); +} + +class StreamSubscriptionStub implements StreamSubscription { + @override + Future cancel() async { + return; + } + + @override + void onData(void Function(T)? handleData) {} + @override + void onError(Function? handleError) {} + @override + void onDone(void Function()? handleDone) {} + @override + void pause([Future? resumeSignal]) {} + @override + void resume() {} + @override + bool get isPaused { + return true; + } + + @override + Future asFuture([E? futureValue]) async { + E resultValue; + if (futureValue == null) { + resultValue = futureValue as dynamic; + } else { + resultValue = futureValue; + } + return Future.value(resultValue); + } +} diff --git a/test/tcp_test.mocks.dart b/test/tcp_test.mocks.dart new file mode 100644 index 0000000..1f146b3 --- /dev/null +++ b/test/tcp_test.mocks.dart @@ -0,0 +1,1245 @@ +// Mocks generated by Mockito 5.4.2 from annotations +// in camel/test/tcp_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; +import 'dart:convert' as _i3; +import 'dart:io' as _i2; +import 'dart:typed_data' as _i6; + +import 'package:camel/command.dart' as _i8; +import 'package:camel/message.dart' as _i5; +import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i7; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeInternetAddress_0 extends _i1.SmartFake + implements _i2.InternetAddress { + _FakeInternetAddress_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeEncoding_1 extends _i1.SmartFake implements _i3.Encoding { + _FakeEncoding_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeStreamSubscription_2 extends _i1.SmartFake + implements _i4.StreamSubscription { + _FakeStreamSubscription_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeFuture_3 extends _i1.SmartFake implements _i4.Future { + _FakeFuture_3( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeSocket_4 extends _i1.SmartFake implements _i2.Socket { + _FakeSocket_4( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeServerSocket_5 extends _i1.SmartFake implements _i2.ServerSocket { + _FakeServerSocket_5( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeMessageHeader_6 extends _i1.SmartFake implements _i5.MessageHeader { + _FakeMessageHeader_6( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [Socket]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockSocket extends _i1.Mock implements _i2.Socket { + MockSocket() { + _i1.throwOnMissingStub(this); + } + + @override + int get port => (super.noSuchMethod( + Invocation.getter(#port), + returnValue: 0, + ) as int); + @override + int get remotePort => (super.noSuchMethod( + Invocation.getter(#remotePort), + returnValue: 0, + ) as int); + @override + _i2.InternetAddress get address => (super.noSuchMethod( + Invocation.getter(#address), + returnValue: _FakeInternetAddress_0( + this, + Invocation.getter(#address), + ), + ) as _i2.InternetAddress); + @override + _i2.InternetAddress get remoteAddress => (super.noSuchMethod( + Invocation.getter(#remoteAddress), + returnValue: _FakeInternetAddress_0( + this, + Invocation.getter(#remoteAddress), + ), + ) as _i2.InternetAddress); + @override + _i4.Future get done => (super.noSuchMethod( + Invocation.getter(#done), + returnValue: _i4.Future.value(), + ) as _i4.Future); + @override + bool get isBroadcast => (super.noSuchMethod( + Invocation.getter(#isBroadcast), + returnValue: false, + ) as bool); + @override + _i4.Future get length => (super.noSuchMethod( + Invocation.getter(#length), + returnValue: _i4.Future.value(0), + ) as _i4.Future); + @override + _i4.Future get isEmpty => (super.noSuchMethod( + Invocation.getter(#isEmpty), + returnValue: _i4.Future.value(false), + ) as _i4.Future); + @override + _i4.Future<_i6.Uint8List> get first => (super.noSuchMethod( + Invocation.getter(#first), + returnValue: _i4.Future<_i6.Uint8List>.value(_i6.Uint8List(0)), + ) as _i4.Future<_i6.Uint8List>); + @override + _i4.Future<_i6.Uint8List> get last => (super.noSuchMethod( + Invocation.getter(#last), + returnValue: _i4.Future<_i6.Uint8List>.value(_i6.Uint8List(0)), + ) as _i4.Future<_i6.Uint8List>); + @override + _i4.Future<_i6.Uint8List> get single => (super.noSuchMethod( + Invocation.getter(#single), + returnValue: _i4.Future<_i6.Uint8List>.value(_i6.Uint8List(0)), + ) as _i4.Future<_i6.Uint8List>); + @override + _i3.Encoding get encoding => (super.noSuchMethod( + Invocation.getter(#encoding), + returnValue: _FakeEncoding_1( + this, + Invocation.getter(#encoding), + ), + ) as _i3.Encoding); + @override + set encoding(_i3.Encoding? _encoding) => super.noSuchMethod( + Invocation.setter( + #encoding, + _encoding, + ), + returnValueForMissingStub: null, + ); + @override + void destroy() => super.noSuchMethod( + Invocation.method( + #destroy, + [], + ), + returnValueForMissingStub: null, + ); + @override + bool setOption( + _i2.SocketOption? option, + bool? enabled, + ) => + (super.noSuchMethod( + Invocation.method( + #setOption, + [ + option, + enabled, + ], + ), + returnValue: false, + ) as bool); + @override + _i6.Uint8List getRawOption(_i2.RawSocketOption? option) => + (super.noSuchMethod( + Invocation.method( + #getRawOption, + [option], + ), + returnValue: _i6.Uint8List(0), + ) as _i6.Uint8List); + @override + void setRawOption(_i2.RawSocketOption? option) => super.noSuchMethod( + Invocation.method( + #setRawOption, + [option], + ), + returnValueForMissingStub: null, + ); + @override + _i4.Future close() => (super.noSuchMethod( + Invocation.method( + #close, + [], + ), + returnValue: _i4.Future.value(), + ) as _i4.Future); + @override + _i4.Stream<_i6.Uint8List> asBroadcastStream({ + void Function(_i4.StreamSubscription<_i6.Uint8List>)? onListen, + void Function(_i4.StreamSubscription<_i6.Uint8List>)? onCancel, + }) => + (super.noSuchMethod( + Invocation.method( + #asBroadcastStream, + [], + { + #onListen: onListen, + #onCancel: onCancel, + }, + ), + returnValue: _i4.Stream<_i6.Uint8List>.empty(), + ) as _i4.Stream<_i6.Uint8List>); + @override + _i4.StreamSubscription<_i6.Uint8List> listen( + void Function(_i6.Uint8List)? onData, { + Function? onError, + void Function()? onDone, + bool? cancelOnError, + }) => + (super.noSuchMethod( + Invocation.method( + #listen, + [onData], + { + #onError: onError, + #onDone: onDone, + #cancelOnError: cancelOnError, + }, + ), + returnValue: _FakeStreamSubscription_2<_i6.Uint8List>( + this, + Invocation.method( + #listen, + [onData], + { + #onError: onError, + #onDone: onDone, + #cancelOnError: cancelOnError, + }, + ), + ), + ) as _i4.StreamSubscription<_i6.Uint8List>); + @override + _i4.Stream<_i6.Uint8List> where(bool Function(_i6.Uint8List)? test) => + (super.noSuchMethod( + Invocation.method( + #where, + [test], + ), + returnValue: _i4.Stream<_i6.Uint8List>.empty(), + ) as _i4.Stream<_i6.Uint8List>); + @override + _i4.Stream map(S Function(_i6.Uint8List)? convert) => + (super.noSuchMethod( + Invocation.method( + #map, + [convert], + ), + returnValue: _i4.Stream.empty(), + ) as _i4.Stream); + @override + _i4.Stream asyncMap(_i4.FutureOr Function(_i6.Uint8List)? convert) => + (super.noSuchMethod( + Invocation.method( + #asyncMap, + [convert], + ), + returnValue: _i4.Stream.empty(), + ) as _i4.Stream); + @override + _i4.Stream asyncExpand( + _i4.Stream? Function(_i6.Uint8List)? convert) => + (super.noSuchMethod( + Invocation.method( + #asyncExpand, + [convert], + ), + returnValue: _i4.Stream.empty(), + ) as _i4.Stream); + @override + _i4.Stream<_i6.Uint8List> handleError( + Function? onError, { + bool Function(dynamic)? test, + }) => + (super.noSuchMethod( + Invocation.method( + #handleError, + [onError], + {#test: test}, + ), + returnValue: _i4.Stream<_i6.Uint8List>.empty(), + ) as _i4.Stream<_i6.Uint8List>); + @override + _i4.Stream expand(Iterable Function(_i6.Uint8List)? convert) => + (super.noSuchMethod( + Invocation.method( + #expand, + [convert], + ), + returnValue: _i4.Stream.empty(), + ) as _i4.Stream); + @override + _i4.Future pipe(_i4.StreamConsumer<_i6.Uint8List>? streamConsumer) => + (super.noSuchMethod( + Invocation.method( + #pipe, + [streamConsumer], + ), + returnValue: _i4.Future.value(), + ) as _i4.Future); + @override + _i4.Stream transform( + _i4.StreamTransformer<_i6.Uint8List, S>? streamTransformer) => + (super.noSuchMethod( + Invocation.method( + #transform, + [streamTransformer], + ), + returnValue: _i4.Stream.empty(), + ) as _i4.Stream); + @override + _i4.Future<_i6.Uint8List> reduce( + _i6.Uint8List Function( + _i6.Uint8List, + _i6.Uint8List, + )? combine) => + (super.noSuchMethod( + Invocation.method( + #reduce, + [combine], + ), + returnValue: _i4.Future<_i6.Uint8List>.value(_i6.Uint8List(0)), + ) as _i4.Future<_i6.Uint8List>); + @override + _i4.Future fold( + S? initialValue, + S Function( + S, + _i6.Uint8List, + )? combine, + ) => + (super.noSuchMethod( + Invocation.method( + #fold, + [ + initialValue, + combine, + ], + ), + returnValue: _i7.ifNotNull( + _i7.dummyValueOrNull( + this, + Invocation.method( + #fold, + [ + initialValue, + combine, + ], + ), + ), + (S v) => _i4.Future.value(v), + ) ?? + _FakeFuture_3( + this, + Invocation.method( + #fold, + [ + initialValue, + combine, + ], + ), + ), + ) as _i4.Future); + @override + _i4.Future join([String? separator = r'']) => (super.noSuchMethod( + Invocation.method( + #join, + [separator], + ), + returnValue: _i4.Future.value(''), + ) as _i4.Future); + @override + _i4.Future contains(Object? needle) => (super.noSuchMethod( + Invocation.method( + #contains, + [needle], + ), + returnValue: _i4.Future.value(false), + ) as _i4.Future); + @override + _i4.Future forEach(void Function(_i6.Uint8List)? action) => + (super.noSuchMethod( + Invocation.method( + #forEach, + [action], + ), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) as _i4.Future); + @override + _i4.Future every(bool Function(_i6.Uint8List)? test) => + (super.noSuchMethod( + Invocation.method( + #every, + [test], + ), + returnValue: _i4.Future.value(false), + ) as _i4.Future); + @override + _i4.Future any(bool Function(_i6.Uint8List)? test) => + (super.noSuchMethod( + Invocation.method( + #any, + [test], + ), + returnValue: _i4.Future.value(false), + ) as _i4.Future); + @override + _i4.Stream cast() => (super.noSuchMethod( + Invocation.method( + #cast, + [], + ), + returnValue: _i4.Stream.empty(), + ) as _i4.Stream); + @override + _i4.Future> toList() => (super.noSuchMethod( + Invocation.method( + #toList, + [], + ), + returnValue: _i4.Future>.value(<_i6.Uint8List>[]), + ) as _i4.Future>); + @override + _i4.Future> toSet() => (super.noSuchMethod( + Invocation.method( + #toSet, + [], + ), + returnValue: _i4.Future>.value(<_i6.Uint8List>{}), + ) as _i4.Future>); + @override + _i4.Future drain([E? futureValue]) => (super.noSuchMethod( + Invocation.method( + #drain, + [futureValue], + ), + returnValue: _i7.ifNotNull( + _i7.dummyValueOrNull( + this, + Invocation.method( + #drain, + [futureValue], + ), + ), + (E v) => _i4.Future.value(v), + ) ?? + _FakeFuture_3( + this, + Invocation.method( + #drain, + [futureValue], + ), + ), + ) as _i4.Future); + @override + _i4.Stream<_i6.Uint8List> take(int? count) => (super.noSuchMethod( + Invocation.method( + #take, + [count], + ), + returnValue: _i4.Stream<_i6.Uint8List>.empty(), + ) as _i4.Stream<_i6.Uint8List>); + @override + _i4.Stream<_i6.Uint8List> takeWhile(bool Function(_i6.Uint8List)? test) => + (super.noSuchMethod( + Invocation.method( + #takeWhile, + [test], + ), + returnValue: _i4.Stream<_i6.Uint8List>.empty(), + ) as _i4.Stream<_i6.Uint8List>); + @override + _i4.Stream<_i6.Uint8List> skip(int? count) => (super.noSuchMethod( + Invocation.method( + #skip, + [count], + ), + returnValue: _i4.Stream<_i6.Uint8List>.empty(), + ) as _i4.Stream<_i6.Uint8List>); + @override + _i4.Stream<_i6.Uint8List> skipWhile(bool Function(_i6.Uint8List)? test) => + (super.noSuchMethod( + Invocation.method( + #skipWhile, + [test], + ), + returnValue: _i4.Stream<_i6.Uint8List>.empty(), + ) as _i4.Stream<_i6.Uint8List>); + @override + _i4.Stream<_i6.Uint8List> distinct( + [bool Function( + _i6.Uint8List, + _i6.Uint8List, + )? equals]) => + (super.noSuchMethod( + Invocation.method( + #distinct, + [equals], + ), + returnValue: _i4.Stream<_i6.Uint8List>.empty(), + ) as _i4.Stream<_i6.Uint8List>); + @override + _i4.Future<_i6.Uint8List> firstWhere( + bool Function(_i6.Uint8List)? test, { + _i6.Uint8List Function()? orElse, + }) => + (super.noSuchMethod( + Invocation.method( + #firstWhere, + [test], + {#orElse: orElse}, + ), + returnValue: _i4.Future<_i6.Uint8List>.value(_i6.Uint8List(0)), + ) as _i4.Future<_i6.Uint8List>); + @override + _i4.Future<_i6.Uint8List> lastWhere( + bool Function(_i6.Uint8List)? test, { + _i6.Uint8List Function()? orElse, + }) => + (super.noSuchMethod( + Invocation.method( + #lastWhere, + [test], + {#orElse: orElse}, + ), + returnValue: _i4.Future<_i6.Uint8List>.value(_i6.Uint8List(0)), + ) as _i4.Future<_i6.Uint8List>); + @override + _i4.Future<_i6.Uint8List> singleWhere( + bool Function(_i6.Uint8List)? test, { + _i6.Uint8List Function()? orElse, + }) => + (super.noSuchMethod( + Invocation.method( + #singleWhere, + [test], + {#orElse: orElse}, + ), + returnValue: _i4.Future<_i6.Uint8List>.value(_i6.Uint8List(0)), + ) as _i4.Future<_i6.Uint8List>); + @override + _i4.Future<_i6.Uint8List> elementAt(int? index) => (super.noSuchMethod( + Invocation.method( + #elementAt, + [index], + ), + returnValue: _i4.Future<_i6.Uint8List>.value(_i6.Uint8List(0)), + ) as _i4.Future<_i6.Uint8List>); + @override + _i4.Stream<_i6.Uint8List> timeout( + Duration? timeLimit, { + void Function(_i4.EventSink<_i6.Uint8List>)? onTimeout, + }) => + (super.noSuchMethod( + Invocation.method( + #timeout, + [timeLimit], + {#onTimeout: onTimeout}, + ), + returnValue: _i4.Stream<_i6.Uint8List>.empty(), + ) as _i4.Stream<_i6.Uint8List>); + @override + void add(List? data) => super.noSuchMethod( + Invocation.method( + #add, + [data], + ), + returnValueForMissingStub: null, + ); + @override + void write(Object? object) => super.noSuchMethod( + Invocation.method( + #write, + [object], + ), + returnValueForMissingStub: null, + ); + @override + void writeAll( + Iterable? objects, [ + String? separator = r'', + ]) => + super.noSuchMethod( + Invocation.method( + #writeAll, + [ + objects, + separator, + ], + ), + returnValueForMissingStub: null, + ); + @override + void writeln([Object? object = r'']) => super.noSuchMethod( + Invocation.method( + #writeln, + [object], + ), + returnValueForMissingStub: null, + ); + @override + void writeCharCode(int? charCode) => super.noSuchMethod( + Invocation.method( + #writeCharCode, + [charCode], + ), + returnValueForMissingStub: null, + ); + @override + void addError( + Object? error, [ + StackTrace? stackTrace, + ]) => + super.noSuchMethod( + Invocation.method( + #addError, + [ + error, + stackTrace, + ], + ), + returnValueForMissingStub: null, + ); + @override + _i4.Future addStream(_i4.Stream>? stream) => + (super.noSuchMethod( + Invocation.method( + #addStream, + [stream], + ), + returnValue: _i4.Future.value(), + ) as _i4.Future); + @override + _i4.Future flush() => (super.noSuchMethod( + Invocation.method( + #flush, + [], + ), + returnValue: _i4.Future.value(), + ) as _i4.Future); +} + +/// A class which mocks [ServerSocket]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockServerSocket extends _i1.Mock implements _i2.ServerSocket { + MockServerSocket() { + _i1.throwOnMissingStub(this); + } + + @override + int get port => (super.noSuchMethod( + Invocation.getter(#port), + returnValue: 0, + ) as int); + @override + _i2.InternetAddress get address => (super.noSuchMethod( + Invocation.getter(#address), + returnValue: _FakeInternetAddress_0( + this, + Invocation.getter(#address), + ), + ) as _i2.InternetAddress); + @override + bool get isBroadcast => (super.noSuchMethod( + Invocation.getter(#isBroadcast), + returnValue: false, + ) as bool); + @override + _i4.Future get length => (super.noSuchMethod( + Invocation.getter(#length), + returnValue: _i4.Future.value(0), + ) as _i4.Future); + @override + _i4.Future get isEmpty => (super.noSuchMethod( + Invocation.getter(#isEmpty), + returnValue: _i4.Future.value(false), + ) as _i4.Future); + @override + _i4.Future<_i2.Socket> get first => (super.noSuchMethod( + Invocation.getter(#first), + returnValue: _i4.Future<_i2.Socket>.value(_FakeSocket_4( + this, + Invocation.getter(#first), + )), + ) as _i4.Future<_i2.Socket>); + @override + _i4.Future<_i2.Socket> get last => (super.noSuchMethod( + Invocation.getter(#last), + returnValue: _i4.Future<_i2.Socket>.value(_FakeSocket_4( + this, + Invocation.getter(#last), + )), + ) as _i4.Future<_i2.Socket>); + @override + _i4.Future<_i2.Socket> get single => (super.noSuchMethod( + Invocation.getter(#single), + returnValue: _i4.Future<_i2.Socket>.value(_FakeSocket_4( + this, + Invocation.getter(#single), + )), + ) as _i4.Future<_i2.Socket>); + @override + _i4.Future<_i2.ServerSocket> close() => (super.noSuchMethod( + Invocation.method( + #close, + [], + ), + returnValue: _i4.Future<_i2.ServerSocket>.value(_FakeServerSocket_5( + this, + Invocation.method( + #close, + [], + ), + )), + ) as _i4.Future<_i2.ServerSocket>); + @override + _i4.Stream<_i2.Socket> asBroadcastStream({ + void Function(_i4.StreamSubscription<_i2.Socket>)? onListen, + void Function(_i4.StreamSubscription<_i2.Socket>)? onCancel, + }) => + (super.noSuchMethod( + Invocation.method( + #asBroadcastStream, + [], + { + #onListen: onListen, + #onCancel: onCancel, + }, + ), + returnValue: _i4.Stream<_i2.Socket>.empty(), + ) as _i4.Stream<_i2.Socket>); + @override + _i4.StreamSubscription<_i2.Socket> listen( + void Function(_i2.Socket)? onData, { + Function? onError, + void Function()? onDone, + bool? cancelOnError, + }) => + (super.noSuchMethod( + Invocation.method( + #listen, + [onData], + { + #onError: onError, + #onDone: onDone, + #cancelOnError: cancelOnError, + }, + ), + returnValue: _FakeStreamSubscription_2<_i2.Socket>( + this, + Invocation.method( + #listen, + [onData], + { + #onError: onError, + #onDone: onDone, + #cancelOnError: cancelOnError, + }, + ), + ), + ) as _i4.StreamSubscription<_i2.Socket>); + @override + _i4.Stream<_i2.Socket> where(bool Function(_i2.Socket)? test) => + (super.noSuchMethod( + Invocation.method( + #where, + [test], + ), + returnValue: _i4.Stream<_i2.Socket>.empty(), + ) as _i4.Stream<_i2.Socket>); + @override + _i4.Stream map(S Function(_i2.Socket)? convert) => (super.noSuchMethod( + Invocation.method( + #map, + [convert], + ), + returnValue: _i4.Stream.empty(), + ) as _i4.Stream); + @override + _i4.Stream asyncMap(_i4.FutureOr Function(_i2.Socket)? convert) => + (super.noSuchMethod( + Invocation.method( + #asyncMap, + [convert], + ), + returnValue: _i4.Stream.empty(), + ) as _i4.Stream); + @override + _i4.Stream asyncExpand(_i4.Stream? Function(_i2.Socket)? convert) => + (super.noSuchMethod( + Invocation.method( + #asyncExpand, + [convert], + ), + returnValue: _i4.Stream.empty(), + ) as _i4.Stream); + @override + _i4.Stream<_i2.Socket> handleError( + Function? onError, { + bool Function(dynamic)? test, + }) => + (super.noSuchMethod( + Invocation.method( + #handleError, + [onError], + {#test: test}, + ), + returnValue: _i4.Stream<_i2.Socket>.empty(), + ) as _i4.Stream<_i2.Socket>); + @override + _i4.Stream expand(Iterable Function(_i2.Socket)? convert) => + (super.noSuchMethod( + Invocation.method( + #expand, + [convert], + ), + returnValue: _i4.Stream.empty(), + ) as _i4.Stream); + @override + _i4.Future pipe(_i4.StreamConsumer<_i2.Socket>? streamConsumer) => + (super.noSuchMethod( + Invocation.method( + #pipe, + [streamConsumer], + ), + returnValue: _i4.Future.value(), + ) as _i4.Future); + @override + _i4.Stream transform( + _i4.StreamTransformer<_i2.Socket, S>? streamTransformer) => + (super.noSuchMethod( + Invocation.method( + #transform, + [streamTransformer], + ), + returnValue: _i4.Stream.empty(), + ) as _i4.Stream); + @override + _i4.Future<_i2.Socket> reduce( + _i2.Socket Function( + _i2.Socket, + _i2.Socket, + )? combine) => + (super.noSuchMethod( + Invocation.method( + #reduce, + [combine], + ), + returnValue: _i4.Future<_i2.Socket>.value(_FakeSocket_4( + this, + Invocation.method( + #reduce, + [combine], + ), + )), + ) as _i4.Future<_i2.Socket>); + @override + _i4.Future fold( + S? initialValue, + S Function( + S, + _i2.Socket, + )? combine, + ) => + (super.noSuchMethod( + Invocation.method( + #fold, + [ + initialValue, + combine, + ], + ), + returnValue: _i7.ifNotNull( + _i7.dummyValueOrNull( + this, + Invocation.method( + #fold, + [ + initialValue, + combine, + ], + ), + ), + (S v) => _i4.Future.value(v), + ) ?? + _FakeFuture_3( + this, + Invocation.method( + #fold, + [ + initialValue, + combine, + ], + ), + ), + ) as _i4.Future); + @override + _i4.Future join([String? separator = r'']) => (super.noSuchMethod( + Invocation.method( + #join, + [separator], + ), + returnValue: _i4.Future.value(''), + ) as _i4.Future); + @override + _i4.Future contains(Object? needle) => (super.noSuchMethod( + Invocation.method( + #contains, + [needle], + ), + returnValue: _i4.Future.value(false), + ) as _i4.Future); + @override + _i4.Future forEach(void Function(_i2.Socket)? action) => + (super.noSuchMethod( + Invocation.method( + #forEach, + [action], + ), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) as _i4.Future); + @override + _i4.Future every(bool Function(_i2.Socket)? test) => + (super.noSuchMethod( + Invocation.method( + #every, + [test], + ), + returnValue: _i4.Future.value(false), + ) as _i4.Future); + @override + _i4.Future any(bool Function(_i2.Socket)? test) => (super.noSuchMethod( + Invocation.method( + #any, + [test], + ), + returnValue: _i4.Future.value(false), + ) as _i4.Future); + @override + _i4.Stream cast() => (super.noSuchMethod( + Invocation.method( + #cast, + [], + ), + returnValue: _i4.Stream.empty(), + ) as _i4.Stream); + @override + _i4.Future> toList() => (super.noSuchMethod( + Invocation.method( + #toList, + [], + ), + returnValue: _i4.Future>.value(<_i2.Socket>[]), + ) as _i4.Future>); + @override + _i4.Future> toSet() => (super.noSuchMethod( + Invocation.method( + #toSet, + [], + ), + returnValue: _i4.Future>.value(<_i2.Socket>{}), + ) as _i4.Future>); + @override + _i4.Future drain([E? futureValue]) => (super.noSuchMethod( + Invocation.method( + #drain, + [futureValue], + ), + returnValue: _i7.ifNotNull( + _i7.dummyValueOrNull( + this, + Invocation.method( + #drain, + [futureValue], + ), + ), + (E v) => _i4.Future.value(v), + ) ?? + _FakeFuture_3( + this, + Invocation.method( + #drain, + [futureValue], + ), + ), + ) as _i4.Future); + @override + _i4.Stream<_i2.Socket> take(int? count) => (super.noSuchMethod( + Invocation.method( + #take, + [count], + ), + returnValue: _i4.Stream<_i2.Socket>.empty(), + ) as _i4.Stream<_i2.Socket>); + @override + _i4.Stream<_i2.Socket> takeWhile(bool Function(_i2.Socket)? test) => + (super.noSuchMethod( + Invocation.method( + #takeWhile, + [test], + ), + returnValue: _i4.Stream<_i2.Socket>.empty(), + ) as _i4.Stream<_i2.Socket>); + @override + _i4.Stream<_i2.Socket> skip(int? count) => (super.noSuchMethod( + Invocation.method( + #skip, + [count], + ), + returnValue: _i4.Stream<_i2.Socket>.empty(), + ) as _i4.Stream<_i2.Socket>); + @override + _i4.Stream<_i2.Socket> skipWhile(bool Function(_i2.Socket)? test) => + (super.noSuchMethod( + Invocation.method( + #skipWhile, + [test], + ), + returnValue: _i4.Stream<_i2.Socket>.empty(), + ) as _i4.Stream<_i2.Socket>); + @override + _i4.Stream<_i2.Socket> distinct( + [bool Function( + _i2.Socket, + _i2.Socket, + )? equals]) => + (super.noSuchMethod( + Invocation.method( + #distinct, + [equals], + ), + returnValue: _i4.Stream<_i2.Socket>.empty(), + ) as _i4.Stream<_i2.Socket>); + @override + _i4.Future<_i2.Socket> firstWhere( + bool Function(_i2.Socket)? test, { + _i2.Socket Function()? orElse, + }) => + (super.noSuchMethod( + Invocation.method( + #firstWhere, + [test], + {#orElse: orElse}, + ), + returnValue: _i4.Future<_i2.Socket>.value(_FakeSocket_4( + this, + Invocation.method( + #firstWhere, + [test], + {#orElse: orElse}, + ), + )), + ) as _i4.Future<_i2.Socket>); + @override + _i4.Future<_i2.Socket> lastWhere( + bool Function(_i2.Socket)? test, { + _i2.Socket Function()? orElse, + }) => + (super.noSuchMethod( + Invocation.method( + #lastWhere, + [test], + {#orElse: orElse}, + ), + returnValue: _i4.Future<_i2.Socket>.value(_FakeSocket_4( + this, + Invocation.method( + #lastWhere, + [test], + {#orElse: orElse}, + ), + )), + ) as _i4.Future<_i2.Socket>); + @override + _i4.Future<_i2.Socket> singleWhere( + bool Function(_i2.Socket)? test, { + _i2.Socket Function()? orElse, + }) => + (super.noSuchMethod( + Invocation.method( + #singleWhere, + [test], + {#orElse: orElse}, + ), + returnValue: _i4.Future<_i2.Socket>.value(_FakeSocket_4( + this, + Invocation.method( + #singleWhere, + [test], + {#orElse: orElse}, + ), + )), + ) as _i4.Future<_i2.Socket>); + @override + _i4.Future<_i2.Socket> elementAt(int? index) => (super.noSuchMethod( + Invocation.method( + #elementAt, + [index], + ), + returnValue: _i4.Future<_i2.Socket>.value(_FakeSocket_4( + this, + Invocation.method( + #elementAt, + [index], + ), + )), + ) as _i4.Future<_i2.Socket>); + @override + _i4.Stream<_i2.Socket> timeout( + Duration? timeLimit, { + void Function(_i4.EventSink<_i2.Socket>)? onTimeout, + }) => + (super.noSuchMethod( + Invocation.method( + #timeout, + [timeLimit], + {#onTimeout: onTimeout}, + ), + returnValue: _i4.Stream<_i2.Socket>.empty(), + ) as _i4.Stream<_i2.Socket>); +} + +/// A class which mocks [Message]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockMessage extends _i1.Mock implements _i5.Message { + MockMessage() { + _i1.throwOnMissingStub(this); + } + + @override + _i5.MessageHeader get header => (super.noSuchMethod( + Invocation.getter(#header), + returnValue: _FakeMessageHeader_6( + this, + Invocation.getter(#header), + ), + ) as _i5.MessageHeader); + @override + set header(_i5.MessageHeader? _header) => super.noSuchMethod( + Invocation.setter( + #header, + _header, + ), + returnValueForMissingStub: null, + ); + @override + String get body => (super.noSuchMethod( + Invocation.getter(#body), + returnValue: '', + ) as String); + @override + set body(String? _body) => super.noSuchMethod( + Invocation.setter( + #body, + _body, + ), + returnValueForMissingStub: null, + ); + @override + String get message => (super.noSuchMethod( + Invocation.getter(#message), + returnValue: '', + ) as String); +} + +/// A class which mocks [CommandFactory]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockCommandFactory extends _i1.Mock implements _i8.CommandFactory { + MockCommandFactory() { + _i1.throwOnMissingStub(this); + } +} + +/// A class which mocks [Command]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockCommand extends _i1.Mock implements _i8.Command { + MockCommand() { + _i1.throwOnMissingStub(this); + } + + @override + String get command => (super.noSuchMethod( + Invocation.getter(#command), + returnValue: '', + ) as String); + @override + void execute(_i6.Uint8List? data) => super.noSuchMethod( + Invocation.method( + #execute, + [data], + ), + returnValueForMissingStub: null, + ); +}