PUROGU LADESU

ポエムがメインのブログです。

【SpringBoot】Test

package com.example.serversidebbssample

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.test.context.jdbc.Sql
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.ResultMatcher
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*
import org.springframework.test.web.servlet.setup.MockMvcBuilders

@ExtendWith(SpringExtension::class)
@SpringBootTest
class PersonControllerTasks {
    lateinit var mockMvc: MockMvc

    @Autowired
    lateinit var target: PersonController

    @BeforeEach
    fun setup() {
        mockMvc = MockMvcBuilders.standaloneSetup(target).build()
    }

    @Test
    fun getAllPersonsTest() {
        val response = mockMvc.perform(
            get("/all")
        ).andReturn().response

        assertThat(response.status).isEqualTo(HttpStatus.OK.value())
        assertThat(response.contentType).isEqualTo(MediaType.APPLICATION_JSON.toString())
    }

    @Test
    fun addNewPersonTest() {
        val response = mockMvc.perform(
            post("/add").param("name", "aaa")
        ).andReturn().response

        assertThat(response.status).isEqualTo(HttpStatus.OK.value())
        assertThat(response.contentAsString).isEqualTo("Saved")
    }

    // メソッドの前に実行するSQLを指定
    @Test
    @Sql(statements = ["INSERT INTO person (name) VALUES ('update_data');"])
    fun updatePersonTest() {
        val lastPerson: Person = target.personRepository.findAll().last()

        val response = mockMvc.perform(
            post("/update")
                .param("id", lastPerson.id.toString())
                .param("name", "update_data")
        ).andReturn().response

        assertThat(response.status).isEqualTo(HttpStatus.OK.value())
        assertThat(response.contentAsString).isEqualTo("Updated")
    }

    @Test
    fun deleteNoPersonTest() {
        var response = mockMvc.perform(
            post("/delete")
                .param("id", "-1")
        ).andReturn().response

        println(response)

        assertThat(response.status).isEqualTo(HttpStatus.OK.value())
        assertThat(response.contentAsString).isEqualTo("No User")
    }
}

【Kotlin】VSCodeでkotlin拡張を使う

IntelliJを入れたほうが快適だと思うが、VSCodeを使えという指示なので試してみる。

コンパイラをいれる

https://kotlinlang.org/docs/command-line.html#install-the-compiler
Githubよりkotlin-compiler-1.9.23.zipをダウンロードする。

システム環境変数path

コンパイラをおいた場所を環境変数pathに追加する。

C:\kotlinc\bin

https://kino-code.com/course-kotlin03-environment-for-windows/#toc5

CodeRunner拡張をいれる

marketplace.visualstudio.com

設定追加
"code-runner.executorMap" に下記を追加。

"kotlin": "cd $dir && kotlinc-jvm $fileName -include-runtime -d $fileNameWithoutExt.jar && java -jar $fileNameWithoutExt.jar"

jarを作って実行するまでをやってくれる。

Kotlin拡張をいれる

marketplace.visualstudio.com

コンパイルエラーのチェック、候補の表示をしてくれる。
デフォルトではLanguageServerとか設定がオフになってるっぽく何もしてくれれない。
設定を開いてそれぞれ必要そうなのをONにしてく。
VSCodeの再起動を忘れずに。

"kotlin.externalSources.autoConvertToKotlin": true
"kotlin.inlayHints.chainedHints": true
"kotlin.inlayHints.parameterHints": true
"kotlin.inlayHints.typeHints": true
"kotlin.languageServer.enabled": true
"spring.initializr.defaultLanguage": "Kotlin"

IntelliJみたいに引数の名前や型を出してくれたり、型チェックの警告などを出してくれる。関数の候補もでる。
F12で定義に飛ぶことも出来る。いい感じ。

ただちゃんと開発する場合はGradleを使うほうが良いと思われる。

postgresqlメモ

PostgreSQLの使い方 JavaDrive
https://www.javadrive.jp/postgresql/

PostgreSQL日本語ドキュメント
https://www.postgresql.jp/document/

PostgreSQL】データ型一覧
https://plus-info-tech.com/postgresql-typelist


# 文字列や数値の値の入力方法
https://www.javadrive.jp/postgresql/basic/index1.html

エスケープ文字を使う場合はeかEをつける

e'abc\ndef' → 改行がはいる
'abc\ndef' → ただの文字列
'を入れる場合は''にする → isn''t

# データ型
https://www.javadrive.jp/postgresql/type/

数値 integer(int), bigint, numeric(or decimal), real, double
連番 serial, bigserial (手動で指定できるが使用済みとして考慮されないので)
文字列 varchar(255)可変長, char(8)固定長なので空白で埋める, text(無制限)
日付 timestamp, date, time ''で囲む '2024-4-20 10:23:54'
論理値 bool TRUE/FALSEのほか、 true, 't', 'yes', 'y', 'on', 1 が使える
その他 money, bytea, enum, point, cidr, xml, json, integer, text


# スキーマ
https://www.javadrive.jp/postgresql/schema/index1.html

データベースの中にスキーマを作って、テーブルなどのオブジェクトをグループ化出来る
postgres, template0はもともと存在しているデータベース
publicはもともとあるスキーマ。どのロールでも(誰でも)テーブル作成できる。

# ロール
https://www.javadrive.jp/postgresql/role/

ユーザーやグループ。パスワードを設定する。
何が出来るか権限を設定できる。
GRANT SELECT ON ALL TABLES IN SCHEMA schema_name To role_name;
GRANT SELECT, INSERT ON table_name To role_name;
グループ(ロールをロールに所属させる)
grant admin to kuma with admin option;


# テーブル
https://www.javadrive.jp/postgresql/table/

カラムに対して
id serial PRIMARY KEY
id serial UNIQUE
code integer REFERENCES some_table (code) on delete cascade
price integer CHECK (price > 0)

テーブルに対して
PRIMARY KEY (id, branch)
UNIQUE (id, branch)
FOREIGN KEY (code) REFERENCES some_table (code) on delete cascade
CHECK (price > 0)

# 一時テーブル
https://www.javadrive.jp/postgresql/table/index12.html

# 継承
https://www.javadrive.jp/postgresql/table/index13.html

# 変更
https://www.javadrive.jp/postgresql/table/index16.html

ALTER TABLE sample_tbl ADD COLUMN address varchar(10);
ALTER TABLE sample_tbl ALTER address SET DEFAULT '';
ALTER TABLE sample_tbl ALTER create_date SET NOT NULL;
ALTER TABLE sample_tbl ALTER address TYPE text;

ALTER TABLE sample_tbl ADD PRIMARY KEY (u_id);
ALTER TABLE sample_tbl ADD CONSTRAINT pk_sample_tbl PRIMARY KEY (u_id); notnulは勝手につく
ALTER TABLE sample_tbl DROP CONSTRAINT xxx

IDENTITY 自動で値を入れてくれる(serial, AUTO_INCREMENT みたいなもの)
(id int PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, data text)

## インデックス
https://www.javadrive.jp/postgresql/index/index1.html
CREATE INDEX ON sample_tbl (address);

【Python】JSONの要素の実際と期待値の差異を取得する

jsonを並び替える。
片方にしか存在しないオブジェクトを返す。
まあ並び替えなくてもいいんだけど。

with open("actual.json") as f:
    act = json.load(f)
    
with open("expected.json") as f:
    exp = json.load(f)

# 並び替えたい場合
act.sort(key=operator.itemgetter("Name", "Age", "Birthday"))
exp.sort(key=operator.itemgetter("Name", "Age", "Birthday"))
# exp.sort(key=lambda x: (x["Name"], x["Age"]))

# print(json.dumps(act))
# print(json.dumps(exp))

print("only in act. something is missing in expected.json ")
print([x for x in act if x not in exp])
# for x in act:
#     if x not in exp:
#         print(x)

print("only in exp. too much items in expected.json")
print([x for x in exp if x not in act])
# for x in exp:
#     if x not in act:
#         print(x)


actual.json

[
  {
    "Name": "Bob",
    "Age": 30,
    "Birthday": "1994-08-20"
  },
  {
    "Name": "Alice",
    "Age": 25,
    "Birthday": "1999-05-15"
  },
  {
    "Name": "David",
    "Age": 35,
    "Birthday": "1989-03-25"
  },
  {
    "Name": "Eve",
    "Age": 28,
    "Birthday": "1996-11-05"
  }
]

expected.json

[
  {
    "Name": "Alice",
    "Age": 25,
    "Birthday": "1999-05-15"
  },
  {
    "Name": "Bob",
    "Age": 30,
    "Birthday": "1994-08-20"
  },
  {
    "Name": "Charlie",
    "Age": 40,
    "Birthday": "1984-12-10"
  },
  {
    "Name": "David",
    "Age": 35,
    "Birthday": "1989-03-25"
  },
  {
    "Name": "Eve",
    "Age": 28,
    "Birthday": "1996-11-05"
  }
]

VSCodeでAWS EC2に接続する

1.キーペアをローカルに保存

EC2を作成時にローカルに保存する
場所 %userprofile%\.ssh\sshkey.pem

2.ターミナルから接続確認

%userprofile%\.sshに移動しターミナルから実行
ssh -i "sshkey.pem" ec2-user@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.amazonaws.com

3.VSCode拡張機能をインストール

Remote SSH

4.configファイル作成

場所 %userprofile%\.ssh
Hostはただの名前なので自由につける
HostName EC2の情報から取得する
User AmazonLinuxならec2-user
IdentityFile 相対パスだとダメっぽい

Host ec2-test
    HostName ec2-user@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.amazonaws.com
    User ec2-user
    IdentityFile ~/.ssh/sshkey.pem
5.接続

F1 または 左下の青い><ボタン -> Connect to host
上記のconfigファイルを選択

6.ファイルをVSCodeに展開

フォルダを開くで、任意のフォルダを選択

※注意点

EC2を停止・起動をするとIPアドレスが変わってしまう可能性があるため、
その場合はconfigのHostNameを再設定する。

速習Kotlin


* 変数
var xxx

* クラスありきではないのでトップレベルに関数をかける
エントリーポイント
fun main(args: Array<String>) {
    val name: String = "サンタ"
    println("こんちは ${name}さん")
}

*
プリミティブ(基本型)という概念はない
Boolean Byte Short Int Long Floag Double Char -> JVMではプリミティブとなる
String

型指定しなくても、型推論によって型が決まる
型を指定しない場合は初期値は必須

* 数値リテラル
整数: Int 小数点:Doubleが規定
変える場合は接尾辞をつけるL: Long, F: Float

num::classで型を表示

* 文字列リテラル
EscapedString 普通の文字列
RawString ヒアドキュメント
"""で囲む
trimIndent()でインデントを削除できる
trimMargin()で|より前を削除できる

* 文字列テンプレート
 ${val}
前後が空白の場合{}は省略可能だが使わなくて良いかも

* null許容
型名に?をつける Int? String?
ボクシング 基本型->ラッパーオブジェクトへ変換すること
Int -> Int? へ代入すると参照先がかわる??

* 比較
値の比較 == JavaのEquals
参照先の比較 === Javaの==

* Any
どの型でもOK、nullはダメ。Any?はnull許容型のみOK

* スマートキャスト
nullチェックをすればnullでない型として扱える

st2?.length // nullの場合null。nullかどうかチェック。
st2?.length ?: 0 // nullの場合0
st2!!.length // nullの場合例外。強制的に非null型に変換

* キャスト
Javaのように大きい型への暗黙的変換を認めない
明示的にやる
Int -> Long は val.toLong()
Float -> Double は val.toDouble()

* 配列
arrayOf(1, 2, 3)
intArrayOf(1, 2, 3)
set() get() が使える
要素は変えられないのでadd()は使えない

空の配列は要素数を指定し、null許容型のみ
var data: Array<String?> = arrayOfNulls(5)
var data = arrayOfNulls<String>(3)

コンストラクタ(要素数とラムダ)
var arr4 = Array(5, { i -> i * 3})

* コレクション
toList()を使えば別の参照として渡せる

* 定数
変数は var
val Javaのfinalになる(再代入不可)変更不可ではない
まずは valを使うようにする

* const
コンパイル時定数、コンパイル時点で決まっている
トップレベルかobjectのメンバー
基本型orString
getterを持たない


* 3項演算子はないがifが式なのでそれが使える
val sw1 = if (n1 > 0) "good" else "bad"

* Range
1..10 型はIntRange
1 until 10 末尾を含まない
10 downTo 1 減少
1..10 step 2

* ビット演算子
Java -> k& | ^ ~
Kotlin -> and or xor inv

0B0110 or 0B0001
Integer.toBinaryString() 2進数表記に

* while do while は javaと同じ

* if
式なので値を返せる
式として使う場合はif elseを網羅している必要がある

* when
Javaのswitch
breakは不要、defaultでなくelse

val sw3 = when {
        n1 == 8 -> "good"
        n1 < 0 -> "bad"
        else -> "soso"
    }

range, in, !で否定, カンマで列挙も使える
val sw4 = when(point) {
    in 5..9 -> "A"
    2,3 -> "B"
    1 -> "C"
    else -> throw Exception("input out of range")
}

* for
ループ変数はval, varはつけない
for (li in lis) { print(li) }
is.forEach { print(it) }

ラベル構文でfor, whileに名前をつけてbreak,continueの対象を指定できる
outer@while
break@outer

X to X
X in X


## 関数
引数、戻り値の定義は必須
戻り値がないUnitは省略可能

* 単一式の場合
式を{} でなく = の後ろに書く
returnも不要、型も省略可能

* 名前付き引数
イコールで指定
getArea(height = 5)

* 可変長引数
Arrayとして扱える
普通の引数を混在するには、先頭にするか、そうでなければ名前付き引数にする
fun logprint(vararg items: String) {
    items.forEach {
        print(it)
    }
    println()
}

* スプレッド演算子
配列を引数として展開
アスタリスク一個つける *list

* 複数の値を返す
これは一時的なもの以外は使い回さず、データクラスなどを使うべき
Pair<String, Int>
Triple<String, Int, Int>

fun pairRerutn(): Pair<String, Int> {
    val message = "成功"
    val status = 200
    return Pair(message, status)
}

呼び元は分解宣言で受け取る(無視するものは_を置く)
val (message, status) = pairRerutn()

forEachなど引数として関数を受け取るもの

メソッドに関数を渡す
::change
fun change()

普通はラムダ式を渡す
{item: String -> println(item)}

型が明白な場合は省略可能
{item -> println(item)}

一番うしろの引数がラムダ式の場合、括弧の外に出せる
() {item -> println(item)}
引数がラムダ式のみの場合()も省略可能

ラムダの中でreturnするとforEachでなくその外側の関数を抜ける
ラムダのみを抜ける場合はラベル構文を使う
forEach @loop {}
return@loop

* 匿名関数
ラムダは戻り値の型を表現できないのでその場合
fun(num: Int): Int { num }

高階関数を作るには、引数に型を指定し、内部で実行する
fun benchmark(action: () -> Unit): Long {
    action()
}

* インライン関数
関数の受け渡しはオーバーヘッドがあるので、高階関数などは有効
モジュールのサイズは大きくなる



* staticは存在しない

* メンバー関数
Javaではメソッド

* メソッドアクセス修飾子
public 規定(Javaはパッケージ内が規定)
protected 同じクラスとサブクラス(Javaはパッケージ内も可能)
internal 同じモジュール(IntelliJIDEAモジュール、Gradleプロジェクトなどコンパイル単位)
private 同じクラス、インナークラスのprivateは参照不可(Javaは可能


* プロパティ
単なるフィールドでなく、getter setterをもつ
val, varが使用可能。
初期値を入れない場合は、コンストラクタでセットする
field:バッキングフィールド。自動でフィールドを用意してくれる

get() {
    return field
}
set(value) {
    field = value
}

get() = age >= 20

クラス外からは変更不可にする
private set


* プライマリコンストラクター
class Human constructor(name: String, age: Int)
    var name: String
    init {
        this.name = name
    }

class Human(var name: String, var age: Int) {}

initにプライマリコンストラクタの内容を書く
constructorは省略できる
var をつけることで引数がプロパティとなり、渡された値で初期化される

class Human {}

引数がない場合は()を省略できる

複数のコンストラクタを作る場合
最終的に必ずプライマリコンストラクタを呼び出す(別のセカンダリコンストラクタ経由でもOK)
本体が不要な場合は{}は省略可能

constructor(name: String): this(name, 0)

デフォルト値を指定できる
class Human3(val name: String = "None", val age: Int = 0) {

* パッケージ
Javaと違いフォルダ構造とパッケージは対応してなくて良い
トップレベル(パッケージ直下)
public internal
private ファイル内で有効(パッケージ内ではなく)

* インポート
規定のインポート 明示しなくてもインポートされる KotlinStandardLibraryとか
アスタリスクでパッケージ全部インポート
as XXX でエイリアス
staticインポート Javaのようにimport staticはない*を使うだけ。
クラス名なしでstaticメソッドを使うため。


* open
規定では継承不可。Javaのfinalの状態
クラス、関数にopenをつけると継承、オーバーライド可能となる
open class xxx -> class xxx : xxx
open fun xxx -> override fun xxx

class Child : Parent()
()をつけることでコンストラクタを実行できる
これでconstructor(): super() はいらない

final override fun show()
これ以上overrideさせない場合にfinalをつける
クラス自体がopenじゃないと意味ない

* abstract
抽象メソッドを含んだクラスを抽象クラスという
抽象メソッドにはabstractをつける。オーバーライドが必須になる。

* interface
publicのみ(デフォルト)
abstract open は不要

プロパティを持てる(Javaではpublic static finalのみ)
プロパティはoverrideするかコンストラクタで初期化する必要がある

デフォルト実装(オーバーライドしなくても使える)
super.xxx()で呼び出す
名前が競合したら指定 super<Hoge>.xxx()

バッキングフィールドは持てない(他のプロパティを使う)
get() = this.xxx

プロパティの初期値は設定できない。getterを使うとできる
get() = 20


* 型変換
アップキャスト済みで実態が派生クラスであれば
var worker: Worker = BusinessWorker("bb")

スマートキャスト
明示的にキャストせず型をチェックすれば、基底ー>派生として動く
if (worker is BusinessWorker)
        worker.work()

明示的にチェックする場合はasを使う
var business: BusinessWorker = worker as BusinessWorker


## データクラス

プライマリコンストラクタの引数が1個以上
コンストラクタのみなら{}はなくて良い
※コンストラクタで定義していないものは無視される

equals
すべてのプロパティが等しい場合オブジェクトも同一とみなす

componentN
分割代入ができるようになる。
内部的にxxx.component1, xxx.component2, xxx.component3のようにプロパティにアクセス

copy
コピー。引数で変更するプロパティを指定できる。

* オブジェクト宣言
staticクラスが作れる -> トップレベル関数にしてパッケージにまとめる方が良い?
ユーティリティクラス
コンストラクタは無い
継承は可能

object Something
あとは普通のクラスのようにする

* オブジェクト式
object: Something
再利用しないその場限りのクラスを定義する??

* SAM変換
SAMインターフェイス: 一つしか抽象メソッドを持たないインターフェイス
JavaのRunnable Comparator
これをラムダ式に置き換える??

* コンパニオンオブジェクト
クラス内部でオブジェクト宣言することで、インスタンス化せずに呼び出せるメンバーを作れる
(staticメンバー)

class Laptop private constructor(var name: String) {
    companion object Factory {
    companion object { 無名でも良い
        fun getInstance(): Laptop {
            return Laptop("サーフェス")
        }
    }

Laptop.getInstance()

* enum class
シンボルをカンマ区切りで列挙
is で型のチェック可能
name 文字列
ordinal インデックス
entries 列挙
valueOf() 文字列で探す

enum class Season2(val code: Int) {
    SPRING(1),
    SUMMER(2),
    AUTUMN(3),
    WINTER(4);

class MyGen<T>(var value: T) {
val gen2 = MyGen<String>("tomorrow")
val gen3 = MyGen(12.3) // 推測できる場合は型指定を省略できる

typealias で型名を定義できる

Tの後ろまたは、whereで渡せる型を指定した型を継承しているもののみに制限
<T:Hoge>
where T:Hoge, T:Fuga

先頭に<T>を置く
クラスから独立して使える

fun <T> tail(list: Array<T>): T

* in out
Java 配列の型に親子関係にあれば代入できる
Kotlin 代入できない

out その派生型を認める
in その上位型を認める


## その他
* 拡張関数
既存のクラスに関数を追加する
openでなくても良い
自分はthisでアクセスできる

operatorをつけて引数と戻り値をクラスにする
operator fun plus(c: Coordinate): Coordinat

* 入れ子のクラス
入れ子を持つクラスをアウタークラスという
そのクラス専用のクラスとかは中に入れてprivateにする

openの場合はこれで呼べる
MacClass.Iphone()

* インナークラス
innerをつける
アウタークラスのプロパティにアクセスするにはthis@MacClass.nameとする

* 委譲プロパティ
プロパティの後ろにbyで変更時に実行する内容を追加
Delegates.observable("") { xx }
Delegates.vetoable(0) { 判定 } // falseで更新キャンセル

* 遅延プロパティ
初回参照時の処理を書く
インスタンス生成時ではなく、初回参照時に動作し初回以降は同じ値を返す

* プロパティをmapで管理
class Book(private val map: Map<String, Any>){
    val title: String by map
    val price: Int by map
}

* 委譲プロパティの自作
ReadWriteProperty<Any, T> を実装

* 委譲クラス
インターフェイスの実装を別でやる
class XXX: インターフェイス by 実装クラス

【Kotlin】Gradleのdependanciesを反映させる方法

IntelliJ IDEA初心者です。

問題

build.gradle.ktsのdependanciesにarrowを追加したがimportが認識しない。
ビルドしなおしてもダメ。
ChatGPTに教えてもらった。

方法

画面右上の歯車マークの下のベルマークの下の謎アイコンをクリックする。
(よく見るとゾウさんマーク?)
Gradleのタブが開く。
一番左の更新ボタンを押すとリロードされ反映される。

Intellij IDEA

方法2

変更すると右上に更新ボタンが出現するのでこれを押す。