# Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Object.Fetcher
- alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.CommonAPI
- alias Pleroma.Web.OStatus
- alias Pleroma.Web.Websub.WebsubClientSubscription
import Mock
import Pleroma.Factory
user = User.get_cached_by_ap_id(object_data["actor"])
- assert user.info.note_count == 1
+ assert user.note_count == 1
end
test "it works for incoming notices with hashtags" do
end)
end
+ test "it works for incoming listens" do
+ data = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [],
+ "type" => "Listen",
+ "id" => "http://mastodon.example.org/users/admin/listens/1234/activity",
+ "actor" => "http://mastodon.example.org/users/admin",
+ "object" => %{
+ "type" => "Audio",
+ "id" => "http://mastodon.example.org/users/admin/listens/1234",
+ "attributedTo" => "http://mastodon.example.org/users/admin",
+ "title" => "lain radio episode 1",
+ "artist" => "lain",
+ "album" => "lain radio",
+ "length" => 180_000
+ }
+ }
+
+ {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
+
+ object = Object.normalize(activity)
+
+ assert object.data["title"] == "lain radio episode 1"
+ assert object.data["artist"] == "lain"
+ assert object.data["album"] == "lain radio"
+ assert object.data["length"] == 180_000
+ end
+
test "it rewrites Note votes to Answers and increments vote counters on question activities" do
user = insert(:user)
assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2"
end
+ test "it works for incoming unlikes with an existing like activity and a compact object" do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "leave a like pls"})
+
+ like_data =
+ File.read!("test/fixtures/mastodon-like.json")
+ |> Poison.decode!()
+ |> Map.put("object", activity.data["object"])
+
+ {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data)
+
+ data =
+ File.read!("test/fixtures/mastodon-undo-like.json")
+ |> Poison.decode!()
+ |> Map.put("object", like_data["id"])
+ |> Map.put("actor", like_data["actor"])
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["actor"] == "http://mastodon.example.org/users/admin"
+ assert data["type"] == "Undo"
+ assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo"
+ assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2"
+ end
+
test "it works for incoming announces" do
data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!()
assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id
end
+ test "it works for incoming announces with an inlined activity" do
+ data =
+ File.read!("test/fixtures/mastodon-announce-private.json")
+ |> Poison.decode!()
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["actor"] == "http://mastodon.example.org/users/admin"
+ assert data["type"] == "Announce"
+
+ assert data["id"] ==
+ "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
+
+ object = Object.normalize(data["object"])
+
+ assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368"
+ assert object.data["content"] == "this is a private toot"
+ end
+
+ test "it rejects incoming announces with an inlined activity from another origin" do
+ data =
+ File.read!("test/fixtures/bogus-mastodon-announce.json")
+ |> Poison.decode!()
+
+ assert :error = Transmogrifier.handle_incoming(data)
+ end
+
test "it does not clobber the addressing on announce activities" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
+ assert data["id"] == update_data["id"]
+
user = User.get_cached_by_ap_id(data["actor"])
assert user.name == "gargle"
}
]
- assert user.info.banner["url"] == [
+ assert user.banner["url"] == [
%{
"href" =>
"https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
user = User.get_cached_by_ap_id(activity.actor)
- assert User.Info.fields(user.info) == [
+ assert User.fields(user) == [
%{"name" => "foo", "value" => "bar"},
%{"name" => "foo1", "value" => "bar1"}
]
user = User.get_cached_by_ap_id(user.ap_id)
- assert User.Info.fields(user.info) == [
+ assert User.fields(user) == [
%{"name" => "foo", "value" => "updated"},
%{"name" => "foo1", "value" => "updated"}
]
user = User.get_cached_by_ap_id(user.ap_id)
- assert User.Info.fields(user.info) == [
+ assert User.fields(user) == [
%{"name" => "foo", "value" => "updated"},
%{"name" => "foo1", "value" => "updated"}
]
user = User.get_cached_by_ap_id(user.ap_id)
- assert User.Info.fields(user.info) == []
+ assert User.fields(user) == []
end
test "it works for incoming update activities which lock the account" do
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
user = User.get_cached_by_ap_id(data["actor"])
- assert user.info.locked == true
+ assert user.locked == true
end
test "it works for incoming deletes" do
activity = insert(:note_activity)
+ deleting_user = insert(:user)
data =
File.read!("test/fixtures/mastodon-delete.json")
data =
data
|> Map.put("object", object)
- |> Map.put("actor", activity.data["actor"])
+ |> Map.put("actor", deleting_user.ap_id)
- {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
+ {:ok, %Activity{actor: actor, local: false, data: %{"id" => id}}} =
+ Transmogrifier.handle_incoming(data)
+ assert id == data["id"]
refute Activity.get_by_id(activity.id)
+ assert actor == deleting_user.ap_id
end
test "it fails for incoming deletes with spoofed origin" do
assert capture_log(fn ->
:error = Transmogrifier.handle_incoming(data)
end) =~
- "[error] Could not decode user at fetch http://mastodon.example.org/users/gargron, {:error, {:error, :nxdomain}}"
+ "[error] Could not decode user at fetch http://mastodon.example.org/users/gargron, {:error, :nxdomain}"
assert Activity.get_by_id(activity.id)
end
|> Poison.decode!()
|> Map.put("actor", ap_id)
- assert :error == Transmogrifier.handle_incoming(data)
+ assert capture_log(fn ->
+ assert :error == Transmogrifier.handle_incoming(data)
+ end) =~ "Object containment failed"
+
assert User.get_cached_by_ap_id(ap_id)
end
refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
end
+ test "it works for incoming follows to locked account" do
+ pending_follower = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
+ user = insert(:user, locked: true)
+
+ data =
+ File.read!("test/fixtures/mastodon-follow-activity.json")
+ |> Poison.decode!()
+ |> Map.put("object", user.ap_id)
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["type"] == "Follow"
+ assert data["object"] == user.ap_id
+ assert data["state"] == "pending"
+ assert data["actor"] == "http://mastodon.example.org/users/admin"
+
+ assert [^pending_follower] = User.get_follow_requests(user)
+ end
+
test "it works for incoming blocks" do
user = insert(:user)
assert activity.data["object"] == follow_activity.data["id"]
+ assert activity.data["id"] == accept_data["id"]
+
follower = User.get_cached_by_id(follower.id)
assert User.following?(follower, followed) == true
test "it works for incoming accepts which were orphaned" do
follower = insert(:user)
- followed = insert(:user, %{info: %User.Info{locked: true}})
+ followed = insert(:user, locked: true)
{:ok, follow_activity} = ActivityPub.follow(follower, followed)
test "it works for incoming accepts which are referenced by IRI only" do
follower = insert(:user)
- followed = insert(:user, %{info: %User.Info{locked: true}})
+ followed = insert(:user, locked: true)
{:ok, follow_activity} = ActivityPub.follow(follower, followed)
test "it fails for incoming accepts which cannot be correlated" do
follower = insert(:user)
- followed = insert(:user, %{info: %User.Info{locked: true}})
+ followed = insert(:user, locked: true)
accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json")
test "it fails for incoming rejects which cannot be correlated" do
follower = insert(:user)
- followed = insert(:user, %{info: %User.Info{locked: true}})
+ followed = insert(:user, locked: true)
accept_data =
File.read!("test/fixtures/mastodon-reject-activity.json")
test "it works for incoming rejects which are orphaned" do
follower = insert(:user)
- followed = insert(:user, %{info: %User.Info{locked: true}})
+ followed = insert(:user, locked: true)
{:ok, follower} = User.follow(follower, followed)
{:ok, _follow_activity} = ActivityPub.follow(follower, followed)
{:ok, activity} = Transmogrifier.handle_incoming(reject_data)
refute activity.local
+ assert activity.data["id"] == reject_data["id"]
follower = User.get_cached_by_id(follower.id)
test "it works for incoming rejects which are referenced by IRI only" do
follower = insert(:user)
- followed = insert(:user, %{info: %User.Info{locked: true}})
+ followed = insert(:user, locked: true)
{:ok, follower} = User.follow(follower, followed)
{:ok, follow_activity} = ActivityPub.follow(follower, followed)
{:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
object = Object.normalize(activity)
+ note_obj = %{
+ "type" => "Note",
+ "id" => activity.data["id"],
+ "content" => "test post",
+ "published" => object.data["published"],
+ "actor" => AccountView.render("show.json", %{user: user})
+ }
+
message = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"cc" => [user.ap_id],
- "object" => [user.ap_id, object.data["id"]],
+ "object" => [user.ap_id, activity.data["id"]],
"type" => "Flag",
"content" => "blocked AND reported!!!",
"actor" => other_user.ap_id
assert {:ok, activity} = Transmogrifier.handle_incoming(message)
- assert activity.data["object"] == [user.ap_id, object.data["id"]]
+ assert activity.data["object"] == [user.ap_id, note_obj]
assert activity.data["content"] == "blocked AND reported!!!"
assert activity.data["actor"] == other_user.ap_id
assert activity.data["cc"] == [user.ap_id]
end
+
+ test "it correctly processes messages with non-array to field" do
+ user = insert(:user)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "to" => "https://www.w3.org/ns/activitystreams#Public",
+ "type" => "Create",
+ "object" => %{
+ "content" => "blah blah blah",
+ "type" => "Note",
+ "attributedTo" => user.ap_id,
+ "inReplyTo" => nil
+ },
+ "actor" => user.ap_id
+ }
+
+ assert {:ok, activity} = Transmogrifier.handle_incoming(message)
+
+ assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
+ end
+
+ test "it correctly processes messages with non-array cc field" do
+ user = insert(:user)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "to" => user.follower_address,
+ "cc" => "https://www.w3.org/ns/activitystreams#Public",
+ "type" => "Create",
+ "object" => %{
+ "content" => "blah blah blah",
+ "type" => "Note",
+ "attributedTo" => user.ap_id,
+ "inReplyTo" => nil
+ },
+ "actor" => user.ap_id
+ }
+
+ assert {:ok, activity} = Transmogrifier.handle_incoming(message)
+
+ assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"]
+ assert [user.follower_address] == activity.data["to"]
+ end
end
describe "prepare outgoing" do
+ test "it inlines private announced objects" do
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "hey", "visibility" => "private"})
+
+ {:ok, announce_activity, _} = CommonAPI.repeat(activity.id, user)
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data)
+
+ assert modified["object"]["content"] == "hey"
+ assert modified["object"]["actor"] == modified["object"]["attributedTo"]
+ end
+
test "it turns mentions into tags" do
user = insert(:user)
other_user = insert(:user)
assert modified["object"]["actor"] == modified["object"]["attributedTo"]
end
- test "it translates ostatus IDs to external URLs" do
- incoming = File.read!("test/fixtures/incoming_note_activity.xml")
- {:ok, [referent_activity]} = OStatus.handle_incoming(incoming)
-
- user = insert(:user)
-
- {:ok, activity, _} = CommonAPI.favorite(referent_activity.id, user)
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert modified["object"] == "http://gs.example.org:4040/index.php/notice/29"
- end
-
- test "it translates ostatus reply_to IDs to external URLs" do
- incoming = File.read!("test/fixtures/incoming_note_activity.xml")
- {:ok, [referred_activity]} = OStatus.handle_incoming(incoming)
-
- user = insert(:user)
-
- {:ok, activity} =
- CommonAPI.post(user, %{"status" => "HI!", "in_reply_to_status_id" => referred_activity.id})
-
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert modified["object"]["inReplyTo"] == "http://gs.example.org:4040/index.php/notice/29"
- end
-
test "it strips internal hashtag data" do
user = insert(:user)
assert is_nil(modified["bcc"])
end
+
+ test "it can handle Listen activities" do
+ listen_activity = insert(:listen)
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data)
+
+ assert modified["type"] == "Listen"
+
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.listen(user, %{"title" => "lain radio episode 1"})
+
+ {:ok, _modified} = Transmogrifier.prepare_outgoing(activity.data)
+ end
end
describe "user upgrade" do
follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
})
- user_two = insert(:user, %{following: [user.follower_address]})
+ user_two = insert(:user)
+ Pleroma.FollowingRelationship.follow(user_two, user, "accept")
{:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
{:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
user = User.get_cached_by_id(user.id)
- assert user.info.note_count == 1
+ assert user.note_count == 1
{:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
ObanHelpers.perform_all()
- assert user.info.ap_enabled
- assert user.info.note_count == 1
+ assert user.ap_enabled
+ assert user.note_count == 1
assert user.follower_address == "https://niu.moe/users/rye/followers"
assert user.following_address == "https://niu.moe/users/rye/following"
user = User.get_cached_by_id(user.id)
- assert user.info.note_count == 1
+ assert user.note_count == 1
activity = Activity.get_by_id(activity.id)
assert user.follower_address in activity.recipients
"https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
}
]
- } = user.info.banner
+ } = user.banner
refute "..." in activity.recipients
refute user.follower_address in unrelated_activity.recipients
user_two = User.get_cached_by_id(user_two.id)
- assert user.follower_address in user_two.following
- refute "..." in user_two.following
- end
- end
-
- describe "maybe_retire_websub" do
- test "it deletes all websub client subscripitions with the user as topic" do
- subscription = %WebsubClientSubscription{topic: "https://niu.moe/users/rye.atom"}
- {:ok, ws} = Repo.insert(subscription)
-
- subscription = %WebsubClientSubscription{topic: "https://niu.moe/users/pasty.atom"}
- {:ok, ws2} = Repo.insert(subscription)
-
- Transmogrifier.maybe_retire_websub("https://niu.moe/users/rye")
-
- refute Repo.get(WebsubClientSubscription, ws.id)
- assert Repo.get(WebsubClientSubscription, ws2.id)
+ assert User.following?(user_two, user)
+ refute "..." in User.following(user_two)
end
end
"type" => "Announce"
}
- :error = Transmogrifier.handle_incoming(data)
+ assert capture_log(fn ->
+ :error = Transmogrifier.handle_incoming(data)
+ end) =~ "Object containment failed"
end
test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do
"type" => "Announce"
}
- :error = Transmogrifier.handle_incoming(data)
+ assert capture_log(fn ->
+ :error = Transmogrifier.handle_incoming(data)
+ end) =~ "Object containment failed"
end
test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do
"type" => "Announce"
}
- :error = Transmogrifier.handle_incoming(data)
+ assert capture_log(fn ->
+ :error = Transmogrifier.handle_incoming(data)
+ end) =~ "Object containment failed"
end
end
refute recipient.follower_address in fixed_object["to"]
end
end
+
+ describe "fix_summary/1" do
+ test "returns fixed object" do
+ assert Transmogrifier.fix_summary(%{"summary" => nil}) == %{"summary" => ""}
+ assert Transmogrifier.fix_summary(%{"summary" => "ok"}) == %{"summary" => "ok"}
+ assert Transmogrifier.fix_summary(%{}) == %{"summary" => ""}
+ end
+ end
+
+ describe "fix_in_reply_to/2" do
+ clear_config([:instance, :federation_incoming_replies_max_depth])
+
+ setup do
+ data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
+ [data: data]
+ end
+
+ test "returns not modified object when hasn't containts inReplyTo field", %{data: data} do
+ assert Transmogrifier.fix_in_reply_to(data) == data
+ end
+
+ test "returns object with inReplyToAtomUri when denied incoming reply", %{data: data} do
+ Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
+
+ object_with_reply =
+ Map.put(data["object"], "inReplyTo", "https://shitposter.club/notice/2827873")
+
+ modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
+ assert modified_object["inReplyTo"] == "https://shitposter.club/notice/2827873"
+ assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
+
+ object_with_reply =
+ Map.put(data["object"], "inReplyTo", %{"id" => "https://shitposter.club/notice/2827873"})
+
+ modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
+ assert modified_object["inReplyTo"] == %{"id" => "https://shitposter.club/notice/2827873"}
+ assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
+
+ object_with_reply =
+ Map.put(data["object"], "inReplyTo", ["https://shitposter.club/notice/2827873"])
+
+ modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
+ assert modified_object["inReplyTo"] == ["https://shitposter.club/notice/2827873"]
+ assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
+
+ object_with_reply = Map.put(data["object"], "inReplyTo", [])
+ modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
+ assert modified_object["inReplyTo"] == []
+ assert modified_object["inReplyToAtomUri"] == ""
+ end
+
+ test "returns modified object when allowed incoming reply", %{data: data} do
+ object_with_reply =
+ Map.put(
+ data["object"],
+ "inReplyTo",
+ "https://shitposter.club/notice/2827873"
+ )
+
+ Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 5)
+ modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
+
+ assert modified_object["inReplyTo"] ==
+ "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
+
+ assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
+
+ assert modified_object["conversation"] ==
+ "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26"
+
+ assert modified_object["context"] ==
+ "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26"
+ end
+ end
+
+ describe "fix_url/1" do
+ test "fixes data for object when url is map" do
+ object = %{
+ "url" => %{
+ "type" => "Link",
+ "mimeType" => "video/mp4",
+ "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
+ }
+ }
+
+ assert Transmogrifier.fix_url(object) == %{
+ "url" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
+ }
+ end
+
+ test "fixes data for video object" do
+ object = %{
+ "type" => "Video",
+ "url" => [
+ %{
+ "type" => "Link",
+ "mimeType" => "video/mp4",
+ "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
+ },
+ %{
+ "type" => "Link",
+ "mimeType" => "video/mp4",
+ "href" => "https://peertube46fb-ad81-2d4c2d1630e3-240.mp4"
+ },
+ %{
+ "type" => "Link",
+ "mimeType" => "text/html",
+ "href" => "https://peertube.-2d4c2d1630e3"
+ },
+ %{
+ "type" => "Link",
+ "mimeType" => "text/html",
+ "href" => "https://peertube.-2d4c2d16377-42"
+ }
+ ]
+ }
+
+ assert Transmogrifier.fix_url(object) == %{
+ "attachment" => [
+ %{
+ "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4",
+ "mimeType" => "video/mp4",
+ "type" => "Link"
+ }
+ ],
+ "type" => "Video",
+ "url" => "https://peertube.-2d4c2d1630e3"
+ }
+ end
+
+ test "fixes url for not Video object" do
+ object = %{
+ "type" => "Text",
+ "url" => [
+ %{
+ "type" => "Link",
+ "mimeType" => "text/html",
+ "href" => "https://peertube.-2d4c2d1630e3"
+ },
+ %{
+ "type" => "Link",
+ "mimeType" => "text/html",
+ "href" => "https://peertube.-2d4c2d16377-42"
+ }
+ ]
+ }
+
+ assert Transmogrifier.fix_url(object) == %{
+ "type" => "Text",
+ "url" => "https://peertube.-2d4c2d1630e3"
+ }
+
+ assert Transmogrifier.fix_url(%{"type" => "Text", "url" => []}) == %{
+ "type" => "Text",
+ "url" => ""
+ }
+ end
+
+ test "retunrs not modified object" do
+ assert Transmogrifier.fix_url(%{"type" => "Text"}) == %{"type" => "Text"}
+ end
+ end
+
+ describe "get_obj_helper/2" do
+ test "returns nil when cannot normalize object" do
+ assert capture_log(fn ->
+ refute Transmogrifier.get_obj_helper("test-obj-id")
+ end) =~ "Unsupported URI scheme"
+ end
+
+ test "returns {:ok, %Object{}} for success case" do
+ assert {:ok, %Object{}} =
+ Transmogrifier.get_obj_helper("https://shitposter.club/notice/2827873")
+ end
+ end
+
+ describe "fix_attachments/1" do
+ test "returns not modified object" do
+ data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
+ assert Transmogrifier.fix_attachments(data) == data
+ end
+
+ test "returns modified object when attachment is map" do
+ assert Transmogrifier.fix_attachments(%{
+ "attachment" => %{
+ "mediaType" => "video/mp4",
+ "url" => "https://peertube.moe/stat-480.mp4"
+ }
+ }) == %{
+ "attachment" => [
+ %{
+ "mediaType" => "video/mp4",
+ "url" => [
+ %{
+ "href" => "https://peertube.moe/stat-480.mp4",
+ "mediaType" => "video/mp4",
+ "type" => "Link"
+ }
+ ]
+ }
+ ]
+ }
+ end
+
+ test "returns modified object when attachment is list" do
+ assert Transmogrifier.fix_attachments(%{
+ "attachment" => [
+ %{"mediaType" => "video/mp4", "url" => "https://pe.er/stat-480.mp4"},
+ %{"mimeType" => "video/mp4", "href" => "https://pe.er/stat-480.mp4"}
+ ]
+ }) == %{
+ "attachment" => [
+ %{
+ "mediaType" => "video/mp4",
+ "url" => [
+ %{
+ "href" => "https://pe.er/stat-480.mp4",
+ "mediaType" => "video/mp4",
+ "type" => "Link"
+ }
+ ]
+ },
+ %{
+ "href" => "https://pe.er/stat-480.mp4",
+ "mediaType" => "video/mp4",
+ "mimeType" => "video/mp4",
+ "url" => [
+ %{
+ "href" => "https://pe.er/stat-480.mp4",
+ "mediaType" => "video/mp4",
+ "type" => "Link"
+ }
+ ]
+ }
+ ]
+ }
+ end
+ end
+
+ describe "fix_emoji/1" do
+ test "returns not modified object when object not contains tags" do
+ data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
+ assert Transmogrifier.fix_emoji(data) == data
+ end
+
+ test "returns object with emoji when object contains list tags" do
+ assert Transmogrifier.fix_emoji(%{
+ "tag" => [
+ %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}},
+ %{"type" => "Hashtag"}
+ ]
+ }) == %{
+ "emoji" => %{"bib" => "/test"},
+ "tag" => [
+ %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"},
+ %{"type" => "Hashtag"}
+ ]
+ }
+ end
+
+ test "returns object with emoji when object contains map tag" do
+ assert Transmogrifier.fix_emoji(%{
+ "tag" => %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}}
+ }) == %{
+ "emoji" => %{"bib" => "/test"},
+ "tag" => %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"}
+ }
+ end
+ end
end